[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Reka Kovacs via Phabricator via cfe-commits
rnkovacs created this revision.
rnkovacs added reviewers: NoQ, xazax.hun, george.karpenkov.
Herald added subscribers: mikhail.ramalho, a.sidorin, dkrupp, szepet, 
baloghadamsoftware, whisperity.

Previously, the checker only tracked one raw pointer symbol for each container 
object. But member functions returning a pointer to the object's inner buffer 
may be called on the object several times.
These pointer symbols are now collected in a set inside the program state map 
and thus all of them is checked for use-after-free problems.


Repository:
  rC Clang

https://reviews.llvm.org/D49057

Files:
  lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
  test/Analysis/dangling-internal-buffer.cpp

Index: test/Analysis/dangling-internal-buffer.cpp
===
--- test/Analysis/dangling-internal-buffer.cpp
+++ test/Analysis/dangling-internal-buffer.cpp
@@ -108,6 +108,28 @@
   // expected-note@-1 {{Use of memory after it is freed}}
 }
 
+void multiple_symbols(bool Cond) {
+  const char *c1, *d1;
+  {
+std::string s1;
+c1 = s1.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
+d1 = s1.data(); // expected-note {{Pointer to dangling buffer was obtained here}}
+const char *local = s1.c_str();
+consume(local); // no-warning
+  } // expected-note {{Internal buffer is released because the object was destroyed}}
+  // expected-note@-1 {{Internal buffer is released because the object was destroyed}}
+  std::string s2;
+  const char *c2 = s2.c_str();
+  if (Cond) {
+// expected-note@-1 {{Assuming 'Pred' is not equal to 0}} // expected-note@-1 {{Taking true branch}}
+// expected-note@-2 {{Assuming 'Pred' is 0}} // expected-note@-2 {{Taking false branch}}
+consume(c1); // expected-warning {{Use of memory after it is freed}}
+// expected-note@-1 {{Use of memory after it is freed}}
+  } else {
+consume(d1); // expected-warning {{Use of memory after it is freed}}
+  } // expected-note@-1 {{Use of memory after it is freed}}
+}
+
 void deref_after_scope_cstr_ok() {
   const char *c;
   std::string s;
Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
+++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
@@ -24,10 +24,22 @@
 using namespace clang;
 using namespace ento;
 
-// FIXME: member functions that return a pointer to the container's internal
-// buffer may be called on the object many times, so the object's memory
-// region should have a list of pointer symbols associated with it.
-REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)
+typedef llvm::ImmutableSet PtrSet;
+
+// Associate container objects with a set of raw pointer symbols.
+REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)
+
+namespace clang {
+namespace ento {
+template<> struct ProgramStateTrait
+  : public ProgramStatePartialTrait {
+  static void *GDMIndex() {
+static int Index = 0;
+return &Index;
+  }
+};
+} // end namespace ento
+} // end namespace clang
 
 namespace {
 
@@ -60,8 +72,8 @@
 // lookup by region.
 bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
   RawPtrMapTy Map = State->get();
-  for (const auto Entry : Map) {
-if (Entry.second == Sym)
+  for (const auto &Entry : Map) {
+if (Entry.second.contains(Sym))
   return true;
   }
   return false;
@@ -88,32 +100,45 @@
 return;
 
   SVal Obj = ICall->getCXXThisVal();
-  const auto *TypedR = dyn_cast_or_null(Obj.getAsRegion());
-  if (!TypedR)
+  const auto *ObjRegion = dyn_cast_or_null(Obj.getAsRegion());
+  if (!ObjRegion)
 return;
 
-  auto *TypeDecl = TypedR->getValueType()->getAsCXXRecordDecl();
+  auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl();
   if (TypeDecl->getName() != "basic_string")
 return;
 
   ProgramStateRef State = C.getState();
 
   if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
 SVal RawPtr = Call.getReturnValue();
 if (!RawPtr.isUnknown()) {
-  State = State->set(TypedR, RawPtr.getAsSymbol());
-  C.addTransition(State);
+  // Start tracking this raw pointer by adding it to the set of symbols
+  // associated with this container object in the program state map.
+  PtrSet::Factory &F = State->getStateManager().get_context();
+  PtrSet NewSet = F.getEmptySet();
+  if (State->contains(ObjRegion)) {
+NewSet = *State->get(ObjRegion);
+if (NewSet.contains(RawPtr.getAsSymbol()))
+  return;
+  }
+  NewSet = F.add(NewSet, RawPtr.getAsSymbol());
+  if (!NewSet.isEmpty()) {
+State = State->set(ObjRegion, NewSet);
+C.addTransition(State);
+  }
 }
 return;
   }
 
   if (isa(ICall)) {
-if (State->contains(TypedR)) {
-  const SymbolRef *StrBufferPtr 

[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Gábor Horváth via Phabricator via cfe-commits
xazax.hun accepted this revision.
xazax.hun added a comment.
This revision is now accepted and ready to land.

Overall looks good, some nits inline. Let's run it on some projects to exercise 
this change.




Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:27
 
-// FIXME: member functions that return a pointer to the container's internal
-// buffer may be called on the object many times, so the object's memory
-// region should have a list of pointer symbols associated with it.
-REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)
+typedef llvm::ImmutableSet PtrSet;
+

I think we should use `using` now instead of `typedef`.



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:126
+  NewSet = F.add(NewSet, RawPtr.getAsSymbol());
+  if (!NewSet.isEmpty()) {
+State = State->set(ObjRegion, NewSet);

Is it possible here the set to be empty? We just added a new element to it 
above. Maybe turn this into an assert or just omit this if it is impossible?



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:138
   const Expr *Origin = Call.getOriginExpr();
-  State = allocation_state::markReleased(State, *StrBufferPtr, Origin);
-  State = State->remove(TypedR);
+  const PtrSet *PS = State->get(ObjRegion);
+  for (const auto &Symbol : *PS)

Using both contains and get will result in two lookups. Maybe it would be 
better to just use get and check if the result is nullptr?



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:159
 }
+if (State->contains(Entry.first)) {
+  const PtrSet *OldSet = State->get(Entry.first);

Same comment as above.



Comment at: test/Analysis/dangling-internal-buffer.cpp:111
 
+void multiple_symbols(bool Cond) {
+  const char *c1, *d1;

We started to use lowercase letters for variable names. Maybe this is not the 
best, since it is not following the LLVM coding guidelines. So I think it would 
be better to rename this `Cond` to start with a lowercase letter in this patch 
for consistency, and update the tests to follow the LLVM coding styleguide in a 
separate patch later.


Repository:
  rC Clang

https://reviews.llvm.org/D49057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48712: [X86] Lowering integer truncation intrinsics to native IR

2018-07-08 Thread Simon Pilgrim via Phabricator via cfe-commits
RKSimon added a comment.

LGTM - @craig.topper any comments?


https://reviews.llvm.org/D48712



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48712: [X86] Lowering integer truncation intrinsics to native IR

2018-07-08 Thread Craig Topper via Phabricator via cfe-commits
craig.topper accepted this revision.
craig.topper added a comment.
This revision is now accepted and ready to land.

LGTM


https://reviews.llvm.org/D48712



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Reka Kovacs via Phabricator via cfe-commits
rnkovacs updated this revision to Diff 154519.
rnkovacs marked 5 inline comments as done.
rnkovacs edited the summary of this revision.
rnkovacs added a comment.

Addressed comments.


https://reviews.llvm.org/D49057

Files:
  lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
  test/Analysis/dangling-internal-buffer.cpp

Index: test/Analysis/dangling-internal-buffer.cpp
===
--- test/Analysis/dangling-internal-buffer.cpp
+++ test/Analysis/dangling-internal-buffer.cpp
@@ -108,6 +108,30 @@
   // expected-note@-1 {{Use of memory after it is freed}}
 }
 
+void multiple_symbols(bool cond) {
+  const char *c1, *d1;
+  {
+std::string s1;
+c1 = s1.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
+d1 = s1.data(); // expected-note {{Pointer to dangling buffer was obtained here}}
+const char *local = s1.c_str();
+consume(local); // no-warning
+  } // expected-note {{Internal buffer is released because the object was destroyed}}
+  // expected-note@-1 {{Internal buffer is released because the object was destroyed}}
+  std::string s2;
+  const char *c2 = s2.c_str();
+  if (cond) {
+// expected-note@-1 {{Assuming 'cond' is not equal to 0}}
+// expected-note@-2 {{Taking true branch}}
+// expected-note@-3 {{Assuming 'cond' is 0}}
+// expected-note@-4 {{Taking false branch}}
+consume(c1); // expected-warning {{Use of memory after it is freed}}
+// expected-note@-1 {{Use of memory after it is freed}}
+  } else {
+consume(d1); // expected-warning {{Use of memory after it is freed}}
+  } // expected-note@-1 {{Use of memory after it is freed}}
+}
+
 void deref_after_scope_cstr_ok() {
   const char *c;
   std::string s;
Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
+++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
@@ -24,10 +24,22 @@
 using namespace clang;
 using namespace ento;
 
-// FIXME: member functions that return a pointer to the container's internal
-// buffer may be called on the object many times, so the object's memory
-// region should have a list of pointer symbols associated with it.
-REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)
+using PtrSet = llvm::ImmutableSet;
+
+// Associate container objects with a set of raw pointer symbols.
+REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)
+
+namespace clang {
+namespace ento {
+template<> struct ProgramStateTrait
+  : public ProgramStatePartialTrait {
+  static void *GDMIndex() {
+static int Index = 0;
+return &Index;
+  }
+};
+} // end namespace ento
+} // end namespace clang
 
 namespace {
 
@@ -60,8 +72,8 @@
 // lookup by region.
 bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
   RawPtrMapTy Map = State->get();
-  for (const auto Entry : Map) {
-if (Entry.second == Sym)
+  for (const auto &Entry : Map) {
+if (Entry.second.contains(Sym))
   return true;
   }
   return false;
@@ -88,32 +100,43 @@
 return;
 
   SVal Obj = ICall->getCXXThisVal();
-  const auto *TypedR = dyn_cast_or_null(Obj.getAsRegion());
-  if (!TypedR)
+  const auto *ObjRegion = dyn_cast_or_null(Obj.getAsRegion());
+  if (!ObjRegion)
 return;
 
-  auto *TypeDecl = TypedR->getValueType()->getAsCXXRecordDecl();
+  auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl();
   if (TypeDecl->getName() != "basic_string")
 return;
 
   ProgramStateRef State = C.getState();
 
   if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
 SVal RawPtr = Call.getReturnValue();
 if (!RawPtr.isUnknown()) {
-  State = State->set(TypedR, RawPtr.getAsSymbol());
+  // Start tracking this raw pointer by adding it to the set of symbols
+  // associated with this container object in the program state map.
+  PtrSet::Factory &F = State->getStateManager().get_context();
+  PtrSet NewSet = F.getEmptySet();
+  if (State->contains(ObjRegion)) {
+NewSet = *State->get(ObjRegion);
+if (NewSet.contains(RawPtr.getAsSymbol()))
+  return;
+  }
+  NewSet = F.add(NewSet, RawPtr.getAsSymbol());
+  assert(!NewSet.isEmpty());
+  State = State->set(ObjRegion, NewSet);
   C.addTransition(State);
 }
 return;
   }
 
   if (isa(ICall)) {
-if (State->contains(TypedR)) {
-  const SymbolRef *StrBufferPtr = State->get(TypedR);
-  // FIXME: What if Origin is null?
+if (const PtrSet *PS = State->get(ObjRegion)) {
+  // Mark all pointer symbols associated with the deleted object released.
   const Expr *Origin = Call.getOriginExpr();
-  State = allocation_state::markReleased(State, *StrBufferPtr, Origin);
-  State = State->remove(TypedR);
+  for (const auto &Symbol : *PS)
+Sta

[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Reka Kovacs via Phabricator via cfe-commits
rnkovacs added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:126
+  NewSet = F.add(NewSet, RawPtr.getAsSymbol());
+  if (!NewSet.isEmpty()) {
+State = State->set(ObjRegion, NewSet);

xazax.hun wrote:
> Is it possible here the set to be empty? We just added a new element to it 
> above. Maybe turn this into an assert or just omit this if it is impossible?
I'm not sure whether `add()` can fail. I turned it into an assert now and will 
see if it ever fails.


https://reviews.llvm.org/D49057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Gábor Horváth via Phabricator via cfe-commits
xazax.hun added a comment.

Thanks! The changes look good, I forgot to mark one double lookup though in my 
previous review.




Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:121
+  if (State->contains(ObjRegion)) {
+NewSet = *State->get(ObjRegion);
+if (NewSet.contains(RawPtr.getAsSymbol()))

Oh, there is also a double lookup here, sorry I did not spot it in the initial 
review.


https://reviews.llvm.org/D49057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Reka Kovacs via Phabricator via cfe-commits
rnkovacs updated this revision to Diff 154520.
rnkovacs marked an inline comment as done.

https://reviews.llvm.org/D49057

Files:
  lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
  test/Analysis/dangling-internal-buffer.cpp

Index: test/Analysis/dangling-internal-buffer.cpp
===
--- test/Analysis/dangling-internal-buffer.cpp
+++ test/Analysis/dangling-internal-buffer.cpp
@@ -108,6 +108,30 @@
   // expected-note@-1 {{Use of memory after it is freed}}
 }
 
+void multiple_symbols(bool cond) {
+  const char *c1, *d1;
+  {
+std::string s1;
+c1 = s1.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
+d1 = s1.data(); // expected-note {{Pointer to dangling buffer was obtained here}}
+const char *local = s1.c_str();
+consume(local); // no-warning
+  } // expected-note {{Internal buffer is released because the object was destroyed}}
+  // expected-note@-1 {{Internal buffer is released because the object was destroyed}}
+  std::string s2;
+  const char *c2 = s2.c_str();
+  if (cond) {
+// expected-note@-1 {{Assuming 'cond' is not equal to 0}}
+// expected-note@-2 {{Taking true branch}}
+// expected-note@-3 {{Assuming 'cond' is 0}}
+// expected-note@-4 {{Taking false branch}}
+consume(c1); // expected-warning {{Use of memory after it is freed}}
+// expected-note@-1 {{Use of memory after it is freed}}
+  } else {
+consume(d1); // expected-warning {{Use of memory after it is freed}}
+  } // expected-note@-1 {{Use of memory after it is freed}}
+}
+
 void deref_after_scope_cstr_ok() {
   const char *c;
   std::string s;
Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
+++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
@@ -24,10 +24,22 @@
 using namespace clang;
 using namespace ento;
 
-// FIXME: member functions that return a pointer to the container's internal
-// buffer may be called on the object many times, so the object's memory
-// region should have a list of pointer symbols associated with it.
-REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)
+using PtrSet = llvm::ImmutableSet;
+
+// Associate container objects with a set of raw pointer symbols.
+REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)
+
+namespace clang {
+namespace ento {
+template<> struct ProgramStateTrait
+  : public ProgramStatePartialTrait {
+  static void *GDMIndex() {
+static int Index = 0;
+return &Index;
+  }
+};
+} // end namespace ento
+} // end namespace clang
 
 namespace {
 
@@ -61,7 +73,7 @@
 bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
   RawPtrMapTy Map = State->get();
   for (const auto Entry : Map) {
-if (Entry.second == Sym)
+if (Entry.second.contains(Sym))
   return true;
   }
   return false;
@@ -88,32 +100,43 @@
 return;
 
   SVal Obj = ICall->getCXXThisVal();
-  const auto *TypedR = dyn_cast_or_null(Obj.getAsRegion());
-  if (!TypedR)
+  const auto *ObjRegion = dyn_cast_or_null(Obj.getAsRegion());
+  if (!ObjRegion)
 return;
 
-  auto *TypeDecl = TypedR->getValueType()->getAsCXXRecordDecl();
+  auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl();
   if (TypeDecl->getName() != "basic_string")
 return;
 
   ProgramStateRef State = C.getState();
 
   if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
 SVal RawPtr = Call.getReturnValue();
 if (!RawPtr.isUnknown()) {
-  State = State->set(TypedR, RawPtr.getAsSymbol());
+  // Start tracking this raw pointer by adding it to the set of symbols
+  // associated with this container object in the program state map.
+  PtrSet::Factory &F = State->getStateManager().get_context();
+  PtrSet NewSet = F.getEmptySet();
+  if (const PtrSet *OldSet = State->get(ObjRegion)) {
+NewSet = *OldSet;
+if (NewSet.contains(RawPtr.getAsSymbol()))
+  return;
+  }
+  NewSet = F.add(NewSet, RawPtr.getAsSymbol());
+  assert(!NewSet.isEmpty());
+  State = State->set(ObjRegion, NewSet);
   C.addTransition(State);
 }
 return;
   }
 
   if (isa(ICall)) {
-if (State->contains(TypedR)) {
-  const SymbolRef *StrBufferPtr = State->get(TypedR);
-  // FIXME: What if Origin is null?
+if (const PtrSet *PS = State->get(ObjRegion)) {
+  // Mark all pointer symbols associated with the deleted object released.
   const Expr *Origin = Call.getOriginExpr();
-  State = allocation_state::markReleased(State, *StrBufferPtr, Origin);
-  State = State->remove(TypedR);
+  for (const auto Symbol : *PS)
+State = allocation_state::markReleased(State, Symbol, Origin);
+  State = State->remove(ObjRegion);
   C.addTransition(State);
   return;
 }
@@ 

[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Reka Kovacs via Phabricator via cfe-commits
rnkovacs added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:121
+  if (State->contains(ObjRegion)) {
+NewSet = *State->get(ObjRegion);
+if (NewSet.contains(RawPtr.getAsSymbol()))

xazax.hun wrote:
> Oh, there is also a double lookup here, sorry I did not spot it in the 
> initial review.
Thanks for noticing. I should have seen it in the first place :)


https://reviews.llvm.org/D49057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49058: [analyzer] Move DanglingInternalBufferChecker out of alpha

2018-07-08 Thread Reka Kovacs via Phabricator via cfe-commits
rnkovacs created this revision.
rnkovacs added reviewers: NoQ, xazax.hun, george.karpenkov.
Herald added subscribers: mikhail.ramalho, a.sidorin, dkrupp, szepet, 
baloghadamsoftware, whisperity.

Repository:
  rC Clang

https://reviews.llvm.org/D49058

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td


Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -276,6 +276,11 @@
 
 let ParentPackage = Cplusplus in {
 
+def DanglingInternalBufferChecker : Checker<"DanglingInternalBuffer">,
+  HelpText<"Reports the usage of internal raw pointers of C++ containers "
+   "after invalidation.">,
+  DescFile<"DanglingInternalBufferChecker.cpp">;
+
 def NewDeleteChecker : Checker<"NewDelete">,
   HelpText<"Check for double-free and use-after-free problems. Traces memory 
managed by new/delete.">,
   DescFile<"MallocChecker.cpp">;
@@ -300,11 +305,6 @@
 
 let ParentPackage = CplusplusAlpha in {
 
-def DanglingInternalBufferChecker : Checker<"DanglingInternalBuffer">,
-  HelpText<"Check for internal raw pointers of C++ standard library containers 
"
-   "used after deallocation">,
-  DescFile<"DanglingInternalBufferChecker.cpp">;
-
 def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
   HelpText<"Reports destructions of polymorphic objects with a non-virtual "
"destructor in their base class">,


Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -276,6 +276,11 @@
 
 let ParentPackage = Cplusplus in {
 
+def DanglingInternalBufferChecker : Checker<"DanglingInternalBuffer">,
+  HelpText<"Reports the usage of internal raw pointers of C++ containers "
+   "after invalidation.">,
+  DescFile<"DanglingInternalBufferChecker.cpp">;
+
 def NewDeleteChecker : Checker<"NewDelete">,
   HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">,
   DescFile<"MallocChecker.cpp">;
@@ -300,11 +305,6 @@
 
 let ParentPackage = CplusplusAlpha in {
 
-def DanglingInternalBufferChecker : Checker<"DanglingInternalBuffer">,
-  HelpText<"Check for internal raw pointers of C++ standard library containers "
-   "used after deallocation">,
-  DescFile<"DanglingInternalBufferChecker.cpp">;
-
 def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
   HelpText<"Reports destructions of polymorphic objects with a non-virtual "
"destructor in their base class">,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49057: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker

2018-07-08 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ added a comment.

Much symbols!




Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:126
+  NewSet = F.add(NewSet, RawPtr.getAsSymbol());
+  if (!NewSet.isEmpty()) {
+State = State->set(ObjRegion, NewSet);

rnkovacs wrote:
> xazax.hun wrote:
> > Is it possible here the set to be empty? We just added a new element to it 
> > above. Maybe turn this into an assert or just omit this if it is impossible?
> I'm not sure whether `add()` can fail. I turned it into an assert now and 
> will see if it ever fails.
It totally can't. We're just adding an object to a set. What could possibly go 
wrong?



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:32-40
+namespace clang {
+namespace ento {
+template<> struct ProgramStateTrait
+  : public ProgramStatePartialTrait {
+  static void *GDMIndex() {
+static int Index = 0;
+return &Index;

Please add a comment on how this template is useful. This trick is used by some 
checkers, but it's a vry unobvious trick. We should probably add a macro 
for that, i.e. `REGISTER_FACTORY_WITH_PROGRAMSTATE` or something like that.



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:113
-  const SymbolRef *StrBufferPtr = State->get(TypedR);
-  // FIXME: What if Origin is null?
   const Expr *Origin = Call.getOriginExpr();

Maybe turn the FIXME into a NOTE or something like that. It indeed seems fine, 
but let's still make sure the reader realizes that there's a subtle potential 
problem here.



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:115
 SVal RawPtr = Call.getReturnValue();
 if (!RawPtr.isUnknown()) {
+  // Start tracking this raw pointer by adding it to the set of symbols

I'd much rather unwrap the symbol here, i.e. `if (SymbolRef Sym = 
RawPtr.getAsSymbol())`. A lot of other cornercases may occur if the 
implementation is accidentally inlined (`Undefined`, concrete regions). Also, 
speculatively, `.getAsSymbol(/* search for symbolic base = */ true)` for the 
same reason//*//.

If we didn't care about inlined implementations, the `Unknown` check would have 
been redundant. So it should also be safe to straightforwardly ignore inlined 
implementations by consulting `C.wasInlined`, then the presence of the symbol 
can be asserted. But i'd rather speculatively care about inlined 
implementations as long as it seems easy.

__
//*// In fact your code relies on a very wonky implementation detail of our 
`SVal` hierarchy: namely, pointer-type return values of conservatively 
evaluated functions are always expressed as `&SymRegion{conj_$N}` 
and never as `&element{SymRegion{conj_$N}, 0 S32b, pointee 
type}`. Currently nobody knows the rules under which zero element regions are 
added in different parts of the analyzer, i.e. what is the "canonical" 
representation of the symbolic pointer, though i made a few attempts to 
speculate.



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:119
+  PtrSet::Factory &F = State->getStateManager().get_context();
+  PtrSet NewSet = F.getEmptySet();
+  if (const PtrSet *OldSet = State->get(ObjRegion)) {

My favorite idiom for such cases, looks a bit cleaner:
```
const PtrSet *SetPtr = State->get(ObjRegion)
PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet()
```



Comment at: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp:122
+NewSet = *OldSet;
+if (NewSet.contains(RawPtr.getAsSymbol()))
+  return;

This `contains` check is very unlikely to yield true because if the 
implementation is not inlined, the symbol is newly born. I'd much rather skip 
the check; it doesn't sound like it'd make things any faster.

Even better, let's assert that: `assert(C.wasInlined || !Set.contains(Sym))`. 
It'll probably help us catch some "reincarnated symbol" bugs in the core.


https://reviews.llvm.org/D49057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49059: [MinGW] Skip adding default win32 api libraries if -lwindowsapp is specified

2018-07-08 Thread Martin Storsjö via Phabricator via cfe-commits
mstorsjo created this revision.
mstorsjo added reviewers: rnk, martell, compnerd, smeenai.

In this setup, skip adding all the default windows import libraries, if linking 
to windowsapp (which replaces them, when targeting the windows store/UWP api 
subset).

With GCC, the same is achieved by using a custom spec file, but since clang 
doesn't use spec files, we have to allow other means of overriding what default 
libraries to use (without going all the way to using -nostdlib, which would 
exclude everything). The same approach, in detecting certain user specified 
libraries and omitting others from the defaults, was already used in SVN 
r314138.


Repository:
  rC Clang

https://reviews.llvm.org/D49059

Files:
  lib/Driver/ToolChains/MinGW.cpp
  test/Driver/mingw-windowsapp.c


Index: test/Driver/mingw-windowsapp.c
===
--- /dev/null
+++ test/Driver/mingw-windowsapp.c
@@ -0,0 +1,6 @@
+// RUN: %clang -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck 
-check-prefix=CHECK_DEFAULT %s
+// RUN: %clang -v -target i686-pc-windows-gnu -### %s -lwindowsapp 2>&1 | 
FileCheck -check-prefix=CHECK_WINDOWSAPP %s
+
+// CHECK_DEFAULT: "-lmsvcrt" "-ladvapi32" "-lshell32" "-luser32" "-lkernel32" 
"-lmingw32"
+// CHECK_WINDOWSAPP: "-lwindowsapp" "-lmingw32"
+// CHECK_WINDOWSAPP-SAME: "-lmsvcrt" "-lmingw32"
Index: lib/Driver/ToolChains/MinGW.cpp
===
--- lib/Driver/ToolChains/MinGW.cpp
+++ lib/Driver/ToolChains/MinGW.cpp
@@ -201,6 +201,11 @@
   CmdArgs.push_back("-Bdynamic");
   }
 
+  bool HasWindowsApp = false;
+  for (auto Lib : Args.getAllArgValues(options::OPT_l))
+if (Lib == "windowsapp")
+  HasWindowsApp = true;
+
   if (!Args.hasArg(options::OPT_nostdlib)) {
 if (!Args.hasArg(options::OPT_nodefaultlibs)) {
   if (Args.hasArg(options::OPT_static))
@@ -223,15 +228,17 @@
   if (Args.hasArg(options::OPT_pthread))
 CmdArgs.push_back("-lpthread");
 
-  // add system libraries
-  if (Args.hasArg(options::OPT_mwindows)) {
-CmdArgs.push_back("-lgdi32");
-CmdArgs.push_back("-lcomdlg32");
+  if (!HasWindowsApp) {
+// add system libraries
+if (Args.hasArg(options::OPT_mwindows)) {
+  CmdArgs.push_back("-lgdi32");
+  CmdArgs.push_back("-lcomdlg32");
+}
+CmdArgs.push_back("-ladvapi32");
+CmdArgs.push_back("-lshell32");
+CmdArgs.push_back("-luser32");
+CmdArgs.push_back("-lkernel32");
   }
-  CmdArgs.push_back("-ladvapi32");
-  CmdArgs.push_back("-lshell32");
-  CmdArgs.push_back("-luser32");
-  CmdArgs.push_back("-lkernel32");
 
   if (Args.hasArg(options::OPT_static))
 CmdArgs.push_back("--end-group");


Index: test/Driver/mingw-windowsapp.c
===
--- /dev/null
+++ test/Driver/mingw-windowsapp.c
@@ -0,0 +1,6 @@
+// RUN: %clang -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DEFAULT %s
+// RUN: %clang -v -target i686-pc-windows-gnu -### %s -lwindowsapp 2>&1 | FileCheck -check-prefix=CHECK_WINDOWSAPP %s
+
+// CHECK_DEFAULT: "-lmsvcrt" "-ladvapi32" "-lshell32" "-luser32" "-lkernel32" "-lmingw32"
+// CHECK_WINDOWSAPP: "-lwindowsapp" "-lmingw32"
+// CHECK_WINDOWSAPP-SAME: "-lmsvcrt" "-lmingw32"
Index: lib/Driver/ToolChains/MinGW.cpp
===
--- lib/Driver/ToolChains/MinGW.cpp
+++ lib/Driver/ToolChains/MinGW.cpp
@@ -201,6 +201,11 @@
   CmdArgs.push_back("-Bdynamic");
   }
 
+  bool HasWindowsApp = false;
+  for (auto Lib : Args.getAllArgValues(options::OPT_l))
+if (Lib == "windowsapp")
+  HasWindowsApp = true;
+
   if (!Args.hasArg(options::OPT_nostdlib)) {
 if (!Args.hasArg(options::OPT_nodefaultlibs)) {
   if (Args.hasArg(options::OPT_static))
@@ -223,15 +228,17 @@
   if (Args.hasArg(options::OPT_pthread))
 CmdArgs.push_back("-lpthread");
 
-  // add system libraries
-  if (Args.hasArg(options::OPT_mwindows)) {
-CmdArgs.push_back("-lgdi32");
-CmdArgs.push_back("-lcomdlg32");
+  if (!HasWindowsApp) {
+// add system libraries
+if (Args.hasArg(options::OPT_mwindows)) {
+  CmdArgs.push_back("-lgdi32");
+  CmdArgs.push_back("-lcomdlg32");
+}
+CmdArgs.push_back("-ladvapi32");
+CmdArgs.push_back("-lshell32");
+CmdArgs.push_back("-luser32");
+CmdArgs.push_back("-lkernel32");
   }
-  CmdArgs.push_back("-ladvapi32");
-  CmdArgs.push_back("-lshell32");
-  CmdArgs.push_back("-luser32");
-  CmdArgs.push_back("-lkernel32");
 
   if (Args.hasArg(options::OPT_static))
 CmdArgs.push_back("--end-group");
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-

[PATCH] D47632: [ASTImporter] Refactor Decl creation

2018-07-08 Thread Aleksei Sidorin via Phabricator via cfe-commits
a_sidorin added a comment.

Hi Gabor,
I like the new syntax. There are some comments inline; most of them are just 
stylish.




Comment at: lib/AST/ASTImporter.cpp:94
+  void updateAttrAndFlags(const Decl *From, Decl *To) {
+// check if some flags or attrs are new in 'From' and copy into 'To'
+// FIXME: other flags or attrs?

Comments should be complete sentences: start with a capital and end with a 
period.



Comment at: lib/AST/ASTImporter.cpp:114
+
+// Always use theses functions to create a Decl during import. There are
+// certain tasks which must be done after the Decl was created, e.g. we

these?



Comment at: lib/AST/ASTImporter.cpp:161
+  ToD->IdentifierNamespace = FromD->IdentifierNamespace;
+  if (FromD->hasAttrs())
+for (const Attr *FromAttr : FromD->getAttrs())

Should we move the below operations into `updateAttrAndFlags()` and use it 
instead?



Comment at: lib/AST/ASTImporter.cpp:1587
   StructuralEquivalenceContext Ctx(
   Importer.getFromContext(), Importer.getToContext(),
+  Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer),

(Thinking out loud) We need to introduce some method to return 
`StructuralEquivalenceContext` in ASTImporter. But this is an item for a 
separate patch, not this one.



Comment at: lib/AST/ASTImporter.cpp:1890
   TypedefNameDecl *ToTypedef;
-  if (IsAlias)
-ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, StartL, Loc,
-  Name.getAsIdentifierInfo(), TInfo);
-  else
-ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
-StartL, Loc,
-Name.getAsIdentifierInfo(),
-TInfo);
+  if (IsAlias && GetImportedOrCreateDecl(
+ ToTypedef, D, Importer.getToContext(), DC, StartL, Loc,

This is not strictly equivalent to the source condition. If 
GetImportedOrCreateDecl returns false, we'll fall to the `else` branch, and it 
doesn't seem correct to me.



Comment at: lib/AST/ASTImporter.cpp:4274
+  TemplateParams))
+return ToD;
+  return ToD;

Can we just ignore the return value by casting it to void here and in similar 
cases?



Comment at: lib/AST/ASTStructuralEquivalence.cpp:895
+  // If any of the records has external storage and we do a minimal check (or
+  // AST import) we assmue they are equivalent. (If we didn't have this
+  // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger

assume


Repository:
  rC Clang

https://reviews.llvm.org/D47632



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48628: [AST] Structural equivalence of methods

2018-07-08 Thread Aleksei Sidorin via Phabricator via cfe-commits
a_sidorin added inline comments.



Comment at: unittests/AST/StructuralEquivalenceTest.cpp:489
+
+TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
+  auto t = makeNamedDecls(

balazske wrote:
> a_sidorin wrote:
> > Could you add a comment why this test is disabled?
> Methods are not checked, there was no decision about to include this check or 
> not. The problem was related to performance overhead and if order-independent 
> check of methods is needed. (ASTImporter should keep order of imported fields 
> and methods.) (This test is about equivalence of `foo`.)
You mean that imported decl have other order of methods? Do you mean implicit 
methods (because I see only a single method here)? If so, could you please note 
this in the comment?


Repository:
  rC Clang

https://reviews.llvm.org/D48628



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48941: [ASTImporter] import FunctionDecl end locations

2018-07-08 Thread Aleksei Sidorin via Phabricator via cfe-commits
a_sidorin accepted this revision.
a_sidorin added a comment.

LGTM too. Thank you!


Repository:
  rC Clang

https://reviews.llvm.org/D48941



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


r336518 - [clang-format/ObjC] Fix counting selector name parts for ObjC

2018-07-08 Thread Jacek Olesiak via cfe-commits
Author: jolesiak
Date: Sun Jul  8 22:58:51 2018
New Revision: 336518

URL: http://llvm.org/viewvc/llvm-project?rev=336518&view=rev
Log:
[clang-format/ObjC] Fix counting selector name parts for ObjC

Summary:
Counts selector parts also for method declarations and counts correctly for 
methods without arguments.
This is an internal change and doesn't influence formatting on its own (at the 
current state). Its lack would be visible after applying D48719.

Reviewers: benhamilton, klimek

Reviewed By: benhamilton

Subscribers: acoomans, cfe-commits

Differential Revision: https://reviews.llvm.org/D48716

Modified:
cfe/trunk/lib/Format/FormatToken.h
cfe/trunk/lib/Format/TokenAnnotator.cpp

Modified: cfe/trunk/lib/Format/FormatToken.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=336518&r1=336517&r2=336518&view=diff
==
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Sun Jul  8 22:58:51 2018
@@ -243,8 +243,9 @@ struct FormatToken {
   /// e.g. because several of them are block-type.
   unsigned LongestObjCSelectorName = 0;
 
-  /// How many parts ObjC selector have (i.e. how many parameters method
-  /// has).
+  /// If this is the first ObjC selector name in an ObjC method
+  /// definition or call, this contains the number of parts that the whole
+  /// selector consist of.
   unsigned ObjCSelectorNameParts = 0;
 
   /// Stores the number of required fake parentheses and the

Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=336518&r1=336517&r2=336518&view=diff
==
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Sun Jul  8 22:58:51 2018
@@ -515,11 +515,23 @@ private:
 }
 Left->MatchingParen = CurrentToken;
 CurrentToken->MatchingParen = Left;
+// FirstObjCSelectorName is set when a colon is found. This does
+// not work, however, when the method has no parameters.
+// Here, we set FirstObjCSelectorName when the end of the method call 
is
+// reached, in case it was not set already.
+if (!Contexts.back().FirstObjCSelectorName) {
+FormatToken* Previous = CurrentToken->getPreviousNonComment();
+if (Previous && Previous->is(TT_SelectorName)) {
+  Previous->ObjCSelectorNameParts = 1;
+  Contexts.back().FirstObjCSelectorName = Previous;
+}
+} else {
+  Left->ParameterCount =
+  Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
+}
 if (Contexts.back().FirstObjCSelectorName) {
   Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
   Contexts.back().LongestObjCSelectorName;
-  Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts =
-  Left->ParameterCount;
   if (Left->BlockParameterCount > 1)
 Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
 }
@@ -539,11 +551,6 @@ private:
  TT_DesignatedInitializerLSquare)) {
   Left->Type = TT_ObjCMethodExpr;
   StartsObjCMethodExpr = true;
-  // ParameterCount might have been set to 1 before expression was
-  // recognized as ObjCMethodExpr (as '1 + number of commas' formula is
-  // used for other expression types). Parameter counter has to be,
-  // therefore, reset to 0.
-  Left->ParameterCount = 0;
   Contexts.back().ColonIsObjCMethodExpr = true;
   if (Parent && Parent->is(tok::r_paren))
 // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
@@ -617,12 +624,12 @@ private:
   }
 
   void updateParameterCount(FormatToken *Left, FormatToken *Current) {
+// For ObjC methods, the number of parameters is calculated differently as
+// method declarations have a different structure (the parameters are not
+// inside a bracket scope).
 if (Current->is(tok::l_brace) && Current->BlockKind == BK_Block)
   ++Left->BlockParameterCount;
-if (Left->Type == TT_ObjCMethodExpr) {
-  if (Current->is(tok::colon))
-++Left->ParameterCount;
-} else if (Current->is(tok::comma)) {
+if (Current->is(tok::comma)) {
   ++Left->ParameterCount;
   if (!Left->Role)
 Left->Role.reset(new CommaSeparatedList(Style));
@@ -718,6 +725,7 @@ private:
Contexts.back().LongestObjCSelectorName)
 Contexts.back().LongestObjCSelectorName =
 Tok->Previous->ColumnWidth;
+  ++Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
 }
   } else if (Contexts.back().ColonIsForRangeExpr) {
 Tok->Type = TT_RangeBasedF

[PATCH] D48716: [clang-format/ObjC] Fix counting selector name parts for ObjC

2018-07-08 Thread Jacek Olesiak via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL336518: [clang-format/ObjC] Fix counting selector name parts 
for ObjC (authored by jolesiak, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D48716

Files:
  cfe/trunk/lib/Format/FormatToken.h
  cfe/trunk/lib/Format/TokenAnnotator.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -515,11 +515,23 @@
 }
 Left->MatchingParen = CurrentToken;
 CurrentToken->MatchingParen = Left;
+// FirstObjCSelectorName is set when a colon is found. This does
+// not work, however, when the method has no parameters.
+// Here, we set FirstObjCSelectorName when the end of the method call 
is
+// reached, in case it was not set already.
+if (!Contexts.back().FirstObjCSelectorName) {
+FormatToken* Previous = CurrentToken->getPreviousNonComment();
+if (Previous && Previous->is(TT_SelectorName)) {
+  Previous->ObjCSelectorNameParts = 1;
+  Contexts.back().FirstObjCSelectorName = Previous;
+}
+} else {
+  Left->ParameterCount =
+  Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
+}
 if (Contexts.back().FirstObjCSelectorName) {
   Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
   Contexts.back().LongestObjCSelectorName;
-  Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts =
-  Left->ParameterCount;
   if (Left->BlockParameterCount > 1)
 Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
 }
@@ -539,11 +551,6 @@
  TT_DesignatedInitializerLSquare)) {
   Left->Type = TT_ObjCMethodExpr;
   StartsObjCMethodExpr = true;
-  // ParameterCount might have been set to 1 before expression was
-  // recognized as ObjCMethodExpr (as '1 + number of commas' formula is
-  // used for other expression types). Parameter counter has to be,
-  // therefore, reset to 0.
-  Left->ParameterCount = 0;
   Contexts.back().ColonIsObjCMethodExpr = true;
   if (Parent && Parent->is(tok::r_paren))
 // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
@@ -617,12 +624,12 @@
   }
 
   void updateParameterCount(FormatToken *Left, FormatToken *Current) {
+// For ObjC methods, the number of parameters is calculated differently as
+// method declarations have a different structure (the parameters are not
+// inside a bracket scope).
 if (Current->is(tok::l_brace) && Current->BlockKind == BK_Block)
   ++Left->BlockParameterCount;
-if (Left->Type == TT_ObjCMethodExpr) {
-  if (Current->is(tok::colon))
-++Left->ParameterCount;
-} else if (Current->is(tok::comma)) {
+if (Current->is(tok::comma)) {
   ++Left->ParameterCount;
   if (!Left->Role)
 Left->Role.reset(new CommaSeparatedList(Style));
@@ -718,6 +725,7 @@
Contexts.back().LongestObjCSelectorName)
 Contexts.back().LongestObjCSelectorName =
 Tok->Previous->ColumnWidth;
+  ++Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
 }
   } else if (Contexts.back().ColonIsForRangeExpr) {
 Tok->Type = TT_RangeBasedForLoopColon;
Index: cfe/trunk/lib/Format/FormatToken.h
===
--- cfe/trunk/lib/Format/FormatToken.h
+++ cfe/trunk/lib/Format/FormatToken.h
@@ -243,8 +243,9 @@
   /// e.g. because several of them are block-type.
   unsigned LongestObjCSelectorName = 0;
 
-  /// How many parts ObjC selector have (i.e. how many parameters method
-  /// has).
+  /// If this is the first ObjC selector name in an ObjC method
+  /// definition or call, this contains the number of parts that the whole
+  /// selector consist of.
   unsigned ObjCSelectorNameParts = 0;
 
   /// Stores the number of required fake parentheses and the


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -515,11 +515,23 @@
 }
 Left->MatchingParen = CurrentToken;
 CurrentToken->MatchingParen = Left;
+// FirstObjCSelectorName is set when a colon is found. This does
+// not work, however, when the method has no parameters.
+// Here, we set FirstObjCSelectorName when the end of the method call is
+// reached, in case it was not set already.
+if (!Contexts.back().FirstObjCSelectorName) {
+FormatToken* Previous = Curr

r336519 - [clang-format/ObjC] Prohibit breaking after a bracket opening ObjC method expression

2018-07-08 Thread Jacek Olesiak via cfe-commits
Author: jolesiak
Date: Sun Jul  8 23:04:58 2018
New Revision: 336519

URL: http://llvm.org/viewvc/llvm-project?rev=336519&view=rev
Log:
[clang-format/ObjC] Prohibit breaking after a bracket opening ObjC method 
expression

Summary:
Don't break after a "[" opening an ObjC method expression.
Tests are added in D48719 where formatting is improved (to avoid adding and 
changing tests immediately).

Reviewers: benhamilton, klimek

Reviewed By: benhamilton

Subscribers: acoomans, cfe-commits

Differential Revision: https://reviews.llvm.org/D48718

Modified:
cfe/trunk/lib/Format/ContinuationIndenter.cpp

Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=336519&r1=336518&r2=336519&view=diff
==
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Sun Jul  8 23:04:58 2018
@@ -321,6 +321,9 @@ bool ContinuationIndenter::canBreak(cons
   State.Stack.back().NoLineBreakInOperand)
 return false;
 
+  if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr))
+return false;
+
   return !State.Stack.back().NoLineBreak;
 }
 


___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48718: [clang-format/ObjC] Prohibit breaking after a bracket opening ObjC method expression

2018-07-08 Thread Jacek Olesiak via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL336519: [clang-format/ObjC] Prohibit breaking after a 
bracket opening ObjC method… (authored by jolesiak, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D48718

Files:
  cfe/trunk/lib/Format/ContinuationIndenter.cpp


Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -321,6 +321,9 @@
   State.Stack.back().NoLineBreakInOperand)
 return false;
 
+  if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr))
+return false;
+
   return !State.Stack.back().NoLineBreak;
 }
 


Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -321,6 +321,9 @@
   State.Stack.back().NoLineBreakInOperand)
 return false;
 
+  if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr))
+return false;
+
   return !State.Stack.back().NoLineBreak;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48628: [AST] Structural equivalence of methods

2018-07-08 Thread Balázs Kéri via Phabricator via cfe-commits
balazske marked an inline comment as done.
balazske added inline comments.



Comment at: unittests/AST/StructuralEquivalenceTest.cpp:489
+
+TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
+  auto t = makeNamedDecls(

a_sidorin wrote:
> balazske wrote:
> > a_sidorin wrote:
> > > Could you add a comment why this test is disabled?
> > Methods are not checked, there was no decision about to include this check 
> > or not. The problem was related to performance overhead and if 
> > order-independent check of methods is needed. (ASTImporter should keep 
> > order of imported fields and methods.) (This test is about equivalence of 
> > `foo`.)
> You mean that imported decl have other order of methods? Do you mean implicit 
> methods (because I see only a single method here)? If so, could you please 
> note this in the comment?
The problem with the ordering is in general at structural equivalence check. If 
a complex structure is imported with ASTImporter the ordering of fields and 
methods may change in the imported class (relative to the to-be imported) after 
the import. Either order-independent check is needed in structural equivalence 
check to match two classes with same methods but in different order, or import 
should not change ordering. Currently none of these is implemented, methods are 
not checked at all. The `foo`s in this test should be non-equivalent because 
one different method `x`.


Repository:
  rC Clang

https://reviews.llvm.org/D48628



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47632: [ASTImporter] Refactor Decl creation

2018-07-08 Thread Balázs Kéri via Phabricator via cfe-commits
balazske added inline comments.



Comment at: lib/AST/ASTImporter.cpp:6905
 Decl *ToD = Pos->second;
+// FIXME: remove this call from this function
 ASTNodeImporter(*this).ImportDefinitionIfNeeded(FromD, ToD);

I think this comment is not needed (or with other text). There is a case when 
`GetAlreadyImportedOrNull` is called during import of a Decl that is already 
imported but its definition is not yet completely imported. If this call is 
here we have after `GetAlreadyImportedOrNull` a Decl with complete definition. 
(Name of the function is still bad: It does not only "get" but makes update 
too. The `ImportDefinitionIfNeeded` call can be moved into the decl create 
function?)


Repository:
  rC Clang

https://reviews.llvm.org/D47632



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


r336520 - [clang-format/ObjC] Improve split priorities for ObjC methods

2018-07-08 Thread Jacek Olesiak via cfe-commits
Author: jolesiak
Date: Sun Jul  8 23:54:52 2018
New Revision: 336520

URL: http://llvm.org/viewvc/llvm-project?rev=336520&view=rev
Log:
[clang-format/ObjC] Improve split priorities for ObjC methods

Reduce penalty for aligning ObjC method arguments using the colon alignment as
this is the canonical way.

Trying to fit a whole expression into one line should not force other line
breaks (e.g. when ObjC method expression is a part of other expression).

Modified:
cfe/trunk/lib/Format/FormatToken.h
cfe/trunk/lib/Format/TokenAnnotator.cpp
cfe/trunk/unittests/Format/FormatTestObjC.cpp

Modified: cfe/trunk/lib/Format/FormatToken.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=336520&r1=336519&r2=336520&view=diff
==
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Sun Jul  8 23:54:52 2018
@@ -248,6 +248,11 @@ struct FormatToken {
   /// selector consist of.
   unsigned ObjCSelectorNameParts = 0;
 
+  /// The 0-based index of the parameter/argument. For ObjC it is set
+  /// for the selector name token.
+  /// For now calculated only for ObjC.
+  unsigned ParameterIndex = 0;
+
   /// Stores the number of required fake parentheses and the
   /// corresponding operator precedence.
   ///

Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=336520&r1=336519&r2=336520&view=diff
==
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Sun Jul  8 23:54:52 2018
@@ -725,6 +725,8 @@ private:
Contexts.back().LongestObjCSelectorName)
 Contexts.back().LongestObjCSelectorName =
 Tok->Previous->ColumnWidth;
+  Tok->Previous->ParameterIndex =
+  Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
   ++Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
 }
   } else if (Contexts.back().ColonIsForRangeExpr) {
@@ -2142,8 +2144,20 @@ void TokenAnnotator::calculateFormatting
 // FIXME: Only calculate this if CanBreakBefore is true once static
 // initializers etc. are sorted out.
 // FIXME: Move magic numbers to a better place.
-Current->SplitPenalty = 20 * Current->BindingStrength +
-splitPenalty(Line, *Current, InFunctionDecl);
+
+// Reduce penalty for aligning ObjC method arguments using the colon
+// alignment as this is the canonical way (still prefer fitting everything
+// into one line if possible). Trying to fit a whole expression into one
+// line should not force other line breaks (e.g. when ObjC method
+// expression is a part of other expression).
+Current->SplitPenalty = splitPenalty(Line, *Current, InFunctionDecl);
+if (Style.Language == FormatStyle::LK_ObjC &&
+Current->is(TT_SelectorName) && Current->ParameterIndex > 0) {
+  if (Current->ParameterIndex == 1)
+Current->SplitPenalty += 5 * Current->BindingStrength;
+} else {
+  Current->SplitPenalty += 20 * Current->BindingStrength;
+}
 
 Current = Current->Next;
   }

Modified: cfe/trunk/unittests/Format/FormatTestObjC.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestObjC.cpp?rev=336520&r1=336519&r2=336520&view=diff
==
--- cfe/trunk/unittests/Format/FormatTestObjC.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestObjC.cpp Sun Jul  8 23:54:52 2018
@@ -678,6 +678,18 @@ TEST_F(FormatTestObjC, FormatObjCMethodE
   verifyFormat("[(id)foo bar:(id) ? baz : quux];");
   verifyFormat("4 > 4 ? (id)a : (id)baz;");
 
+  unsigned PreviousColumnLimit = Style.ColumnLimit;
+  Style.ColumnLimit = 50;
+  // Instead of:
+  // bool a =
+  // ([object a:42] == 0 || [object a:42
+  //b:42] == 0);
+  verifyFormat("bool a = ([object a:42] == 0 ||\n"
+   "  [object a:42 b:42] == 0);");
+  Style.ColumnLimit = PreviousColumnLimit;
+  verifyFormat("bool a = ([ a] == a ||\n"
+   "  [ a] == );");
+
   // This tests that the formatter doesn't break after "backing" but before 
":",
   // which would be at 80 columns.
   verifyFormat(
@@ -754,11 +766,10 @@ TEST_F(FormatTestObjC, FormatObjCMethodE
   "[self a:aaa, aaa, 
aaa,\n"
   "aaa, aaa, 
aaa,\n"
   "aaa, aaa];");
+
   verifyFormat("[self // break\n"
"  a:a\n"
"aaa:aaa];");
-  verifyFormat("bool a = ([ a] == a