Code completion features missing in 2.5.4

Hello, it seems from my testing that there are a couple code completion features missing from AppCode 2.5.4 (and there was no mention of any fixes to code completion in 2.5.5)

Specifically:

- Pressing Ctrl+Space twice is supposed to do completion based on unimported headers (I assume Ctrl+Space once is supposed to only complete based on current imports)?  In my testing, there is no difference between pressing Ctrl+Space once or twice.  Either way will complete using unimported headers.

- Smart completion (Ctrl+Shift+Space) is supposed to examine local scope variables and chain method calls up to two levels deep to find suggestions of the expected type.  In my testing, only local scope variables themselves, methods chained on Foundation classes, and single depth methods called on self will appear in smart code completion.  So if I have a class in my project called Foo that is defined like this:

@interface Foo : NSObject

@property(nonatomic, copy) NSString *name;

@end

And I call smart code completion after the = sign in the below statement:

-(void) someMethod:(Foo *)foo
{
     NSString* string =
}

I would expect to see "foo.name" in the smart code completion suggestions, but I do not.   Also, pressing the smart completion shortcut a second time doesn't sem to increase the number of suggestions at all, but only reloads the same suggestions that were present after only pressing the shortcut once.

- Smart code completion often suggests symbols of the wrong type.  In the below screenshot, I decalre a variable "something" of type BOOL, and smart complete on the right hand side of the expression.  The first two smart completion suggestions are enum constants, not BOOL types at all (see screenshot).  Further down, the suggestions list includes some BOOL values, bool values, Boolean values, glBoolean values, NSTextAlignment values, NSCalculationError values, more enum constant values, etc.  See second screenshot below:

Screen Shot 2014-03-05 at 6.44.56 PM.png
Screen Shot 2014-03-05 at 6.41.39 PM.png
I realize that these all could theoretically be a 0 or a 1, just like BOOL, but it seems inappropriate here.  I have also seen smart completion offer me things like a CGRect local variable when it should be suggestion only NSStrings.

Am I missing a setting or something else?  Or are these features not working as expected?

References:

From blog post:  http://blog.jetbrains.com/objc/2012/05/appcode-code-completion-101/


"Trick #3: Smarter completion
Actually there’s more intelligence hidden behind both completion kinds that can be revealed by pressing the corresponding shortcut twice.


Press ⌃Space for basic completion twice, and AppCode will find not yet imported symbols (for example, functions) and add the import for you.
If Smart Type completion didn’t suggest you anything, try pressing the same shortcut (⌃⇧Space) one more time: AppCode will look up values of the expected type which can be retrieved through a chained method call."


From blog post:  

http://jetbrains.dzone.com/articles/top-20-code-completions-in-intellij-idea

"Chain completion


Next feature, which makes you even more productive, is Chain completion. If you need to type a chain like getModule().getProject(), just call Smart completion twice. In that case IntelliJ IDEA will scan variables, fields and methods, visible from the context, and offer you a chain, which satisfies expected type.


As you might know, recently there was a plugin for Eclipse Juno, called Code Recommenders. This is quite interesting plugin, which also claims to provide a kind of chain completion. However, it works in a different way. While Code Recommenders suggests only chains of Eclipse SDK APIs classes, IntelliJ IDEA provides chains of any classes from your code."

6 comments

Thanks for the detailed report. We've filed an issue (http://youtrack.jetbrains.com/issue/OC-9337) concerning completion problem with property of a class .
However, I'm afraid there is no error in completion of the asignment to the variable of BOOL. The BOOL is not a dedicated type here it's just typedef of char.

0

Thanks Alexey,

That's an interesting perspective on BOOL matching, and something I was sort of guessing might be the case.  However, in terms of language best practices, and expectations, don't you think it would make sense that only values of YES or NO or return types of BOOL should be smart code completed for BOOL expressions?  All the pieces are there in AppCode:  it already can map usages of a macro identifier (like YES or NO) separately from the type of its value.  Plus, smart completion will suggest only appropriate enum constants in a case like this:

switch (anNSNumberFormatter.numberStyle)
{
     case _
}

smart completion will only suggest enum constants of the type NSNumberFormatterStyle, which matches expectation.  This is depsite the fact that all enum and enum constants are just typdefs of some kind of integer value.  So why does smart completion match BOOL, a typedef of unsigned char, to ANY unsigned char (actually, it looks to me like it matches any symbol equal to 0 or 1), when smart completion matches an enum, a typdef of NSInteger, only to the specific constants that are part of the enum, and ignores all other NSInteger values in the project?

I make this case, because I think maching BOOL to any 0 or 1 may make sense to a compiler, but it's bad coding practice, and frankly, it makes smart completion not look very smart when it happens.

I've also seen cases where smart completion suggests completely mismatched symbols (like CGRect for an NSString expression), which I will document better the next time I encounter it.

Thanks again for you attention to this!!

0

Daniel,

We might want to add some sorting to the list of alternatives for BOOL variables in the future (in order to suggest YES/NO first) but I'm afraid that removing all the alternatives except YES/NO might break someone's workflow. What is about logical expressions where some people might want to use any value != 0 as true?

Concerning enums - they are distinct types (not typedefs) in C/Objective-C with implicit conversion of their members to int. So, it's quite straightforward to handle the example with case statement that you've mentioned.

I've also seen cases where smart completion suggests completely mismatched symbols (like CGRect for an NSString expression), which I will document better the next time I encounter it.

Yes, sometime we may be wrong, so please, send us all such cases.

Best Regards,
Alexey

0

Hi Alexey,

Thanks for the thoughtful response.  I do see your point regarding workflows with any non-zero values being used for true, and similarly, any nil  or 0 values being false.  I wonder how relevant that is to smart completion though...  for me personally, I use the pointer value of any object type as a boolean all the time:  e.g.  if(myObject) {[self doSomething];} assuming that any non zero value is the same as true.

However:

1) If you take any nonzero values (including pointer addresses) and consider them as possible BOOL YESes, and take any 0 or potential 0 or nil values as possible BOOL NOs, you are pretty much going to list every symbol in the project as a smart completion suggestion.  This would be necessary to cover all workflows that use logical boolean expressions where any non-zero value = true, and any zero value = false.

2) Most times logical boolean expression are used, they are not actually assigned to a local BOOL variable.  Example:

if(myArray.count)     // <-- this is just checked inline, not being assigned to a BOOL variable.
{
     //Do something a non-empty array
}


I only see assignment to a BOOL variable in more complex cases, like:

BOOL isValidArray = myArray.count > 0 && myArray.count <20;    // <-- how could we ever expect smart completion to anticipate the right side of this expression as a suggestion for BOOL anyway?

if(isValidArray)
{
     //Do something with valid array
}



3)  In the more common cases, even where the logical boolean result if being calculated based on a non zero value or count, etc. this is explicitly typed as a return type for a method, property, etc.

Example:

@interface NSArray (validationCategory)

-(BOOL) isValidArray;

@end

@implementation NSArray (validationCategory)

-(BOOL) isValidArray
{
     return (self.count > 0 && self.count < 20);  // <-- here the boolean logic usage is explicity cast to BOOL in the return type, so it's easy to smart complete
}

@end


In the above case, I think it would make sense for smart completion to sugggest:

BOOL isValidArray =    //<-- smart completion suggestion:  [myArray isValidArray]


And the fact that I've explicity typed the result to BOOL is a strong hint for the smart completion as to how I intend that value to be used.

So, from my perspective, I would most like to see only BOOL typed values being suggested by smart completion.  And maybe, for the more less obvious cases, pressing smart completion (ctrl+shift+space) a second time would expand the smart completion search scope to include values that aren't eplicitly BOOL typed, but I think, as you suggested, that those should be sorted below actual BOOL types.


Lastly, regarding enums, if they are distinct types, then why do all those enum constants appear as BOOL smart completion suggestions?  In other words, if AppCode is smart enough to know that the enum constants for a specific enum are the only possible values for an argument or variable of that enum type, then why isn't AppCode smart enough to know that those enum constants aren't going to be used for BOOL YES / NO values?

I have not seen real world examples where somone does this:

typedef NS_ENUM(NSInteger, MyEnumType)
{
     MyEnumTypeFirst PossibleValue,
     MyEnumTypeSecondPossibleValue,
     MyEnumTypeThirdPossibleValue
};

MyEnumType selectedValue = MyEnumTypeThirdPossibleValue;

BOOL isAnyEnumValueButFirstPossibleValue = selectedValue; //<-- currently smart completion will suggest selectedValue, MyEnumTypeFirst PossibleValue, MyEnumTypeSecondPossibleValue, etc.



Plus, it is very dangerous to expect that an enum constant that is equal to 0 or 1 today, will still be so tomorrow.  And code should not be written with that assumption ever, really.  Someone could change the above enum to be:

typedef NS_ENUM(NSInteger, MyEnumType)
{
     MyEnumTypeNewDefaultValue,
     MyEnumTypeFirst PossibleValue,
     MyEnumTypeSecondPossibleValue,
     MyEnumTypeThirdPossibleValue
};


In which case, the following logic would then be automatically broken / incorrect:

MyEnumType selectedValue = MyEnumTypeThirdPossibleValue;
BOOL isAnyEnumValueButFirstPossibleValue = selectedValue;  // Returns YES, but would also return YES now if selectedValue == MyEnumTypeFirstPossibleValue


Since MyEnumTypeFirst PossibleValue is now 1 instead of zero and will convert to YES.  My ultimate point being, I don't think enum types or enum constants should EVER be suggested by smart completion as BOOL values.


Thanks again for the well-considered discussion on this!  I do think that smart completion of BOOL types can and should be more focused on the most common usages, and usages that conform to best practices, but I understand that you guys will want to balance this with flexibility for all workflows.  Maybe hiding non BOOL-typed values until smart completion is triggered a second time, and / or sorting the suggestions is a good all-around solution.  Although again, I don't see why it would ever be good to smart suggest enum types or enum constants as BOOL values.

0

Daniel,

Thanks for such a complete investigation of possible behaviour of completion. We'll concider it in our development of next release of AppCode. Here the issue http://youtrack.jetbrains.com/issue/OC-9374

Best Regards,
Alexey

0

Thanks Alexey,  I appreciate the consideration and the creation of a ticket for the issue!

0

Please sign in to leave a comment.