Here's a few ideas, mostly micro details. I haven't quite got the macro 
design sufficiently in my head to respond to that yet.


================
Comment at: test/SemaCXX/warn-consumed-analysis.cpp:46
@@ +45,3 @@
+  if (var.isValid()) { // \
+    \\ expected-warning {{Unnecessary test. Variable 'var' is known to be in 
the 'consumed' state}}
+    *var;
----------------
Line wrapping here is strange (comment, newline escape, then another comment 
starter?). Generally we don't worry about 80 cols in tests, so you can just 
remove the line wrapping.

================
Comment at: include/clang/Analysis/Analyses/Consumed.h:39
@@ +38,3 @@
+    // No state information for the given variable.
+    None,
+    
----------------
See the naming conventions for enumerators here: 
http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly

================
Comment at: include/clang/Analysis/Analyses/Consumed.h:56
@@ +55,3 @@
+    
+    typedef llvm::DenseMap<const VarDecl*, ConsumedState> MapType;
+    typedef std::pair<const VarDecl*, ConsumedState> PairType;
----------------
Might want to run clang-format over the code, it'll add things like the space 
for * here (to become "const VarDecl *")

================
Comment at: include/clang/Analysis/Analyses/Consumed.h:62
@@ +61,3 @@
+    //////////////////
+    // Data Members //
+    //////////////////
----------------
Drop the section headers like this - they're not really done in LLVM code so 
far as I know.

================
Comment at: include/clang/Analysis/Analyses/Consumed.h:73
@@ +72,3 @@
+    ConsumedStateMap(void) {}
+    ConsumedStateMap(ConsumedStateMap &Other) : Map(Other.Map) {}
+    
----------------
I assume this should be a const reference parameter (non-const copy 
constructors are weird)

Better than that - can you just not define either constructor & rely on the 
defaults? That way you should hopefully get a move ctor for free. (OK, granted 
DenseMap would have to be movable for that - but that's someone else's problem 
unless you want to make it yours)

================
Comment at: include/clang/Analysis/Analyses/Consumed.h:72
@@ +71,3 @@
+  public:
+    ConsumedStateMap(void) {}
+    ConsumedStateMap(ConsumedStateMap &Other) : Map(Other.Map) {}
----------------
Drop 'void' from the parameter list. This isn't necessary in C++ & not 
prevalent in the LLVM codebase. (see comment below about removing unnecessarily 
explicit ctor implementations)

================
Comment at: include/clang/Analysis/Analyses/Consumed.h:79
@@ +78,3 @@
+    /// \brief Mark all variables as unknown.
+    void makeUnknown(void);
+    
----------------
Another 'void' in the param list. Consider this general feedback & I won't call 
out any other instances I see.

================
Comment at: lib/Analysis/Consumed.cpp:402
@@ +401,3 @@
+
+void ConsumedStateMap::merge(const ConsumedStateMap *Other) {
+  ConsumedState LocalState;
----------------
Looks like 'Other' is unconditionally dereferenced and thus cannot be null - 
perhaps it should be be passed by const reference instead of pointer?

================
Comment at: lib/Analysis/Consumed.cpp:405
@@ +404,3 @@
+  
+  for (MapType::const_iterator DMI = Other->Map.begin(),
+    DME = Other->Map.end(); DMI != DME; ++DMI) {
----------------
For a short scope iterator, consider just calling it 'I'

================
Comment at: lib/Analysis/Consumed.cpp:408
@@ +407,3 @@
+    
+    PairType OtherPair = *DMI;
+    
----------------
Not strictly unacceptable, but consider not copying this local and just using 
I->first or I->second. For a short loop I personally find it easier to read as 
I can quickly spot the "this is the current element" code" when it directly 
uses the iterator. Open to disagreement/other ideas, though.

================
Comment at: lib/Analysis/Consumed.cpp:414
@@ +413,3 @@
+      Map.insert(OtherPair);
+      
+    } else if (LocalState != OtherPair.second) {
----------------
Unnecessary blank line

================
Comment at: lib/Analysis/Consumed.cpp:412
@@ +411,3 @@
+    
+    if (LocalState == None) {
+      Map.insert(OtherPair);
----------------
Unnecessary { on one expression block

================
Comment at: lib/Analysis/Consumed.cpp:416
@@ +415,3 @@
+    } else if (LocalState != OtherPair.second) {
+      Map.erase(OtherPair.first);
+      Map.insert(PairType(OtherPair.first, Unknown));
----------------
Could make this one line (& drop the braces) by calling setState?

================
Comment at: lib/Analysis/Consumed.cpp:443
@@ +442,3 @@
+    
+    const OptionalNotes &Notes = I->second;
+    S.Diag(I->first.first, I->first.second);
----------------
I'd consider moving this declaration down to just before the loop so it's 
clearer what it's for (& since it's not needed for the intervening line of code 
- so this would adhere to the general principle of least scope)

================
Comment at: lib/Analysis/Consumed.cpp:455
@@ +454,3 @@
+bool ConsumedAnalyzer::isConsumableType(QualType Type) {
+  if (const CXXRecordDecl *Klass =
+    dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl())) {
----------------
It'd be more idiomatic to name this variable "RD".

================
Comment at: lib/Analysis/Consumed.cpp:461
@@ +460,3 @@
+    if (Entry != ConsumableTypeCache.end()) {
+      return (*Entry).second;
+    }
----------------
-> rather than (*x).y

================
Comment at: lib/Analysis/Consumed.cpp:461
@@ +460,3 @@
+    if (Entry != ConsumableTypeCache.end()) {
+      return (*Entry).second;
+    }
----------------
David Blaikie wrote:
> -> rather than (*x).y
remove {} from one line block

================
Comment at: lib/Analysis/Consumed.cpp:458
@@ +457,3 @@
+    
+    CacheMapType::const_iterator Entry = ConsumableTypeCache.find(Klass);
+    
----------------
Microoptimization:

Rather than find+insert, if you use insert here (with a default value for the 
boolean 'value'), test the second element of the pair returned and then 
populate the value if it was newly inserted. Something like this might be nice:

std::pair<CacheMapType::iterator, bool> Entry = 
ConsumableTypeCache.insert(std::make_pair(RD, false));

if (Entry.second)
  Entry.first->second = hasConsumableAttributes(*RD);

return Entry.first->second;

(where the loop over the CXXRecordDecl's methods and attributes is pulled out 
into a 'hasConsumableAttributes' function)

================
Comment at: lib/Analysis/Consumed.cpp:488
@@ +487,3 @@
+
+// FIXME: Make this not generate false positives for while- and for-loops.
+// TODO: Handle other forms of branching with precision, including while- and
----------------
Is this fixme still valid? I remember you spoke to me about this issue & 
thought you'd ended up punting on this & classifying loop blocks as causing an 
"unspecified" state.

================
Comment at: lib/Analysis/Consumed.cpp:455
@@ +454,3 @@
+bool ConsumedAnalyzer::isConsumableType(QualType Type) {
+  if (const CXXRecordDecl *Klass =
+    dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl())) {
----------------
David Blaikie wrote:
> It'd be more idiomatic to name this variable "RD".
There's a function further down ( ConsumedAnalyzer::run) that starts with a 
dyn_cast_or_null and then an "if (!D) return" - this seems tidier than nesting 
the whole body of the function. Consider doing the same here.

================
Comment at: lib/Analysis/Consumed.cpp:530
@@ +529,3 @@
+  
+  if (!D) {
+    return;
----------------
Unnecessary {}. Once you remove those, clang-format should choose whether to 
put the return on the same line as the 'if' or a separate line. I forget which 
way it goes.

================
Comment at: lib/Analysis/Consumed.cpp:523
@@ +522,3 @@
+  
+  BlockInfo.addInfo(  *SI,        CurrStates);
+  BlockInfo.addInfo(*++SI, ElseOrMergeStates);
----------------
This indentation isn't really common in LLVM - clang-format should choose 
appropriately.

================
Comment at: lib/Analysis/Consumed.cpp:513
@@ +512,3 @@
+      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, Consumed);
+  
+    } else {
----------------
Trailing blank line in a block seems strange (& there's a few more blank lines 
than I'd expect here - could be wrong though. Again, whatever clang-format 
does, I'm OK with (though I'm not sure it touches blank lines, in which case 
I'll express some preferences))

================
Comment at: lib/Analysis/Consumed.cpp:565
@@ +564,3 @@
+    
+    // TODO: Remove any variables that have reached the end of their
+    //       lifetimes from the state map. (Deferred)
----------------
Any idea how bad this'll hurt the compiler for large functions? I assume we 
only track variables with these annotations - so we're not going to kill the 
compiler tomorrow since nothing is annotated, right?

================
Comment at: lib/Analysis/Consumed.cpp:574
@@ +573,3 @@
+    
+    } else if (CurrBlock->succ_size() == 2) {
+      // Handle while- and for-loops.
----------------
Should this case just be moved to the end of this if/else if chain and just be 
an unconditional 'else'?

(& what happens if there are more than 2 successors? (switch block?))

================
Comment at: lib/Analysis/Consumed.cpp:595
@@ +594,3 @@
+  // Delete the last existing state map.
+  delete CurrStates;
+  
----------------
An owning smart pointer would be nice - perhaps CurrStates should be an 
OwningPtr<T>?

Will this lead to a double-delete when you cleanup the contents of BlockInfo 
(hmm, don't seem to be cleaning those up at all)? I'd like a bit more clear 
ownership (perhaps keeping the ConsumedStateMaps directly in the BlockInfo, 
rather than pointers)

================
Comment at: lib/Analysis/Consumed.cpp:641
@@ +640,3 @@
+bool isTestingFunction(const CXXMethodDecl *Method) {
+  if (Method->hasAttr<TestsUnconsumedAttr>()) {
+    return true;
----------------
just "return Method->hasAttr<TestsUnconsumedAttr>();" instead? Or perhaps skip 
the function and make this call directly at the callsites if it's sufficiently 
legible.

================
Comment at: lib/Sema/SemaDeclAttr.cpp:1017
@@ +1016,3 @@
+
+  if (not isa<CXXMethodDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<
----------------
not -> !

(& several more)

================
Comment at: lib/Sema/SemaDeclAttr.cpp:1030
@@ +1029,3 @@
+                                     const AttributeList &Attr) {
+  // Handle functions with the CALLABLE_ALWAYS attribute.
+  
----------------
Comment (& the one up at 1009) seem a bit unnecessary. The function name is 
self explanatory.

================
Comment at: lib/Sema/SemaDeclAttr.cpp:1076
@@ +1075,3 @@
+
+  if (not checkAttributeNumArgs(S, Attr, 0)) {
+    return;
----------------
More one-statement blocks with {}

================
Comment at: test/SemaCXX/warn-consumed-analysis.cpp:33
@@ +32,3 @@
+  if (var0.isValid()) { // \
+    \\ expected-warning {{Unnecessary test. Variable 'var0' is known to be in 
the 'consumed' state}}
+    *var0;
----------------
I think we should drop the "unnecessary test" warning for now. Feel free to 
leave a comment where it would go (probably not even to the level of FIXME, 
just "A warning could be emitted here about a constant test, but care should be 
taken regarding things such as macro expansions & templates.")

================
Comment at: test/SemaCXX/warn-consumed-analysis.cpp:35
@@ +34,3 @@
+    *var0;
+    *var1;  // expected-warning {{Invocation of method 'operator*' on object 
'var1' while it is in the 'consumed' state}}
+    
----------------
I wonder whether there's a way we could make these diagnostics more legible for 
the unique_ptr case. Could we have some verbs in the attributes? (I guess at 
that point we'd need a class level attribute for a consumable type - which 
would make it easier to decide whether a type was consumable (save you the 
member search). Is there any other way in which we'd benefit from/use a class 
level attribute?)

================
Comment at: test/SemaCXX/warn-consumed-analysis.cpp:73
@@ +72,3 @@
+  
+  *var; // expected-warning {{Invocation of method 'operator*' on object 'var' 
while it is in an unknown state}}
+}
----------------
As we discussed - unknown state objects should allow all operations (operations 
allowable only on valid or only on invalid objects)

================
Comment at: test/SemaCXX/warn-consumed-parsing.cpp:10
@@ +9,3 @@
+  void Consumes(void)        __attribute__ ((consumes(42))); // \
+  // expected-error {{attribute takes no arguments}}
+  bool TestsUnconsumed(void) __attribute__ ((tests_unconsumed(42))); // \
----------------
Weird line wrapping again. If you'd really like to put these on separate lines 
you can use the @-1 notation (check other tests for examples - I think that's 
the syntax) to refer to lines by offset, rather than the current line.

If you're going to do that, I'd consider putting the comment above the line, 
rather than below.

================
Comment at: lib/Analysis/Consumed.cpp:52
@@ +51,3 @@
+
+//////////////////////
+// Helper Functions //
----------------
more big headers we don't tend to write - file-local functions are basically by 
definition 'helper functions'.

================
Comment at: lib/Analysis/Consumed.cpp:60
@@ +59,3 @@
+      return "none";
+    
+    case consumed::Unknown:
----------------
Clang-format should tidy this up, probably dropping the empty lines & maybe 
one-lining the case+returns (& perhaps outdenting the cases to line up with the 
switch - at least I think that's LLVM's preferred style)

================
Comment at: lib/Analysis/Consumed.cpp:103
@@ +102,3 @@
+    ConsumedStateMap *StateMap) : Analyzer(Analyzer), StateMap(StateMap) {
+    ModeStack.push_back(Disabled);
+  }
----------------
Could do this in the ctor init list with "ModeStack(1, Disabled)" but I don't 
know if that's much/any better.

Or you could call "reset" to keep the functionality in one place.

================
Comment at: lib/Analysis/Consumed.cpp:149
@@ +148,3 @@
+    unsigned NumArgParamPairs =
+      std::min(Call->getNumArgs(), FunDecl->getNumParams());
+    
----------------
Could this ever be less than Call->getNumArgs? (perhaps with variadic 
functions?)

================
Comment at: lib/Analysis/Consumed.cpp:190
@@ +189,3 @@
+  
+  if (const FunctionDecl *FunDecl =
+    dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
----------------
consider having a short return with an inverted condition here, then outdenting 
the body of this instead of having it all inside the 'if'

================
Comment at: lib/Analysis/Consumed.cpp:195
@@ +194,3 @@
+    //       have to check for the different attributes and change the behavior
+    //       bellow. (Deferred)
+    if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return false;
----------------
FIXMEs are by definition deferred, so you don't really need "(Deferred)".

================
Comment at: lib/Analysis/Consumed.cpp:199
@@ +198,3 @@
+    if (const DeclRefExpr *DeclRef =
+      dyn_cast_or_null<DeclRefExpr>(Call->getArg(0))) {
+    
----------------
Another possible early return.

================
Comment at: lib/Analysis/Consumed.cpp:201
@@ +200,3 @@
+    
+      if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) {
+        switch (StateMap->getState(Var)) {
----------------
& a 3rd

================
Comment at: lib/Analysis/Consumed.cpp:361
@@ +360,3 @@
+    // Merge the new state map with the existing one, and then free the new 
map.
+    (*Entry).second->merge(StateMap);
+    delete StateMap;
----------------
(*x).y -> x->y

================
Comment at: lib/Analysis/Consumed.cpp:367
@@ +366,3 @@
+ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
+  ConsumedStateMap *RetValue = (*Map.find(Block)).second;
+  
----------------
(*x).y -> x->y

================
Comment at: lib/Analysis/Consumed.cpp:382
@@ +381,3 @@
+  if (Entry != Map.end()) {
+    return (*Entry).second;
+    
----------------
(*x).y -> x->y

================
Comment at: lib/Analysis/Consumed.cpp:384
@@ +383,3 @@
+    
+  } else {
+    return None;
----------------
Else after return (just write it as "if (x) return; return;" rather than "if 
(x) return; else return;" )

================
Comment at: lib/Analysis/Consumed.cpp:397
@@ +396,3 @@
+    
+    Map.erase(Pair.first);
+    Map.insert(PairType(Pair.first, Unknown));
----------------
Do you need to erase/insert just to change the value? You should just be able 
to do it with "I->second = Unknown";

(oh, you'd need the iterators to be non-const iterators)

================
Comment at: lib/Analysis/Consumed.cpp:425
@@ +424,3 @@
+void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
+  Map.erase(Var);
+  Map.insert(PairType(Var, State));
----------------
Map[Var] = State; should suffice for this function

================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2175
@@ +2174,3 @@
+def warn_use_while_consumed : Warning<
+  "Invocation of method '%0' on object '%1' while it is in the 'consumed' "
+  "state">,
----------------
Notice that other diagnostics don't begin with an uppercase - they're sentence 
fragments, not sentences. Rephrase these diagnostics in a similar manner.

If possible, it'd be nice not to talk about "states" explicitly. Perhaps:

"attempt to use '%0' on a consumed object '%1'" ? Open to other wordsmithing... 


http://llvm-reviews.chandlerc.com/D1233
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to