r267924 - [analyzer] Add path note for localizability checker.

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 28 12:44:40 PDT 2016


Author: dcoughlin
Date: Thu Apr 28 14:44:40 2016
New Revision: 267924

URL: http://llvm.org/viewvc/llvm-project?rev=267924&view=rev
Log:
[analyzer] Add path note for localizability checker.

Add a path note indicating the location of the non-localized string
literal in NonLocalizedStringChecker.

rdar://problem/25981525

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
    cfe/trunk/test/Analysis/localization.m

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp?rev=267924&r1=267923&r2=267924&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp Thu Apr 28 14:44:40 2016
@@ -111,6 +111,30 @@ NonLocalizedStringChecker::NonLocalizedS
                        "Localizability Issue (Apple)"));
 }
 
+namespace {
+class NonLocalizedStringBRVisitor final
+    : public BugReporterVisitorImpl<NonLocalizedStringBRVisitor> {
+
+  const MemRegion *NonLocalizedString;
+  bool Satisfied;
+
+public:
+  NonLocalizedStringBRVisitor(const MemRegion *NonLocalizedString)
+      : NonLocalizedString(NonLocalizedString), Satisfied(false) {
+        assert(NonLocalizedString);
+  }
+
+  PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+                                 const ExplodedNode *Pred,
+                                 BugReporterContext &BRC,
+                                 BugReport &BR) override;
+
+  void Profile(llvm::FoldingSetNodeID &ID) const override {
+    ID.Add(NonLocalizedString);
+  }
+};
+} // End anonymous namespace.
+
 #define NEW_RECEIVER(receiver)                                                 \
   llvm::DenseMap<Selector, uint8_t> &receiver##M =                             \
       UIMethods.insert({&Ctx.Idents.get(#receiver),                            \
@@ -676,6 +700,11 @@ void NonLocalizedStringChecker::reportLo
     R->addRange(M.getSourceRange());
   }
   R->markInteresting(S);
+
+  const MemRegion *StringRegion = S.getAsRegion();
+  if (StringRegion)
+    R->addVisitor(llvm::make_unique<NonLocalizedStringBRVisitor>(StringRegion));
+
   C.emitReport(std::move(R));
 }
 
@@ -866,6 +895,41 @@ void NonLocalizedStringChecker::checkPos
   setNonLocalizedState(sv, C);
 }
 
+PathDiagnosticPiece *
+NonLocalizedStringBRVisitor::VisitNode(const ExplodedNode *Succ,
+                                       const ExplodedNode *Pred,
+                                       BugReporterContext &BRC, BugReport &BR) {
+  if (Satisfied)
+    return nullptr;
+
+  Optional<StmtPoint> Point = Succ->getLocation().getAs<StmtPoint>();
+  if (!Point.hasValue())
+    return nullptr;
+
+  auto *LiteralExpr = dyn_cast<ObjCStringLiteral>(Point->getStmt());
+  if (!LiteralExpr)
+    return nullptr;
+
+  ProgramStateRef State = Succ->getState();
+  SVal LiteralSVal = State->getSVal(LiteralExpr, Succ->getLocationContext());
+  if (LiteralSVal.getAsRegion() != NonLocalizedString)
+    return nullptr;
+
+  Satisfied = true;
+
+  PathDiagnosticLocation L =
+      PathDiagnosticLocation::create(*Point, BRC.getSourceManager());
+
+  if (!L.isValid() || !L.asLocation().isValid())
+    return nullptr;
+
+  auto *Piece = new PathDiagnosticEventPiece(L,
+      "Non-localized string literal here");
+  Piece->addRange(LiteralExpr->getSourceRange());
+
+  return Piece;
+}
+
 namespace {
 class EmptyLocalizationContextChecker
     : public Checker<check::ASTDecl<ObjCImplementationDecl>> {

Modified: cfe/trunk/test/Analysis/localization.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/localization.m?rev=267924&r1=267923&r2=267924&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/localization.m (original)
+++ cfe/trunk/test/Analysis/localization.m Thu Apr 28 14:44:40 2016
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fblocks -analyzer-store=region -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker=alpha.osx.cocoa.localizability.PluralMisuseChecker -verify  %s
+// RUN: %clang_cc1 -analyze -fblocks -analyzer-store=region -analyzer-output=text -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker=alpha.osx.cocoa.localizability.PluralMisuseChecker -verify  %s
 
 // The larger set of tests in located in localization.m. These are tests
 // specific for non-aggressive reporting.
@@ -61,11 +61,26 @@ NSString *KHLocalizedString(NSString* ke
   UILabel *testLabel = [[UILabel alloc] init];
   NSString *bar = NSLocalizedString(@"Hello", @"Comment");
 
-  if (random()) {
-    bar = @"Unlocalized string";
+  if (random()) { // expected-note {{Taking true branch}}
+    bar = @"Unlocalized string"; // expected-note {{Non-localized string literal here}}
   }
 
-  [testLabel setText:bar]; // expected-warning {{User-facing text should use localized string macro}}
+  [testLabel setText:bar]; // expected-warning {{User-facing text should use localized string macro}} expected-note {{User-facing}}
+}
+
+- (void)testMultipleUnlocalizedStringsInSamePath {
+  UILabel *testLabel = [[UILabel alloc] init];
+  NSString *bar = @"Unlocalized string"; // no-note
+
+  bar = @"Unlocalized string"; // expected-note {{Non-localized string literal here}}
+
+  NSString *other = @"Other unlocalized string."; // no-note
+  (void)other;
+
+  NSString *same = @"Unlocalized string"; // no-note
+  (void)same;
+
+  [testLabel setText:bar]; // expected-warning {{User-facing text should use localized string macro}} expected-note {{User-facing}}
 }
 
 - (void)testOneCharacterStringsDoNotGiveAWarning {
@@ -103,14 +118,14 @@ NSString *KHLocalizedString(NSString* ke
 
 - (NSString *)test1:(int)plural {
     if (plural) {
-        return MCLocalizedString(@"TYPE_PLURAL"); // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return MCLocalizedString(@"TYPE_PLURAL"); // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     }
     return MCLocalizedString(@"TYPE");
 }
 
 - (NSString *)test2:(int)numOfReminders {
     if (numOfReminders > 0) {
-        return [NSString stringWithFormat:@"%@, %@", @"Test", (numOfReminders != 1) ? [NSString stringWithFormat:NSLocalizedString(@"%@ Reminders", @"Plural count of reminders"), numOfReminders] : [NSString stringWithFormat:NSLocalizedString(@"1 reminder", @"One reminder")]]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return [NSString stringWithFormat:@"%@, %@", @"Test", (numOfReminders != 1) ? [NSString stringWithFormat:NSLocalizedString(@"%@ Reminders", @"Plural count of reminders"), numOfReminders] : [NSString stringWithFormat:NSLocalizedString(@"1 reminder", @"One reminder")]]; // expected-warning 2 {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note 2 {{Plural}}
     } 
     return nil;
 }
@@ -119,18 +134,18 @@ NSString *KHLocalizedString(NSString* ke
     NSString *count;
     if (self.unreadArticlesCount > 1)
     {
-        count = [count stringByAppendingFormat:@"%@", KHLocalizedString(@"New Stories", @"Plural count for new stories")]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        count = [count stringByAppendingFormat:@"%@", KHLocalizedString(@"New Stories", @"Plural count for new stories")]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     } else {
-        count = [count stringByAppendingFormat:@"%@",  KHLocalizedString(@"New Story", @"One new story")]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        count = [count stringByAppendingFormat:@"%@",  KHLocalizedString(@"New Story", @"One new story")]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     }
 }
 
 - (NSString *)test4:(int)count {
     if ( count == 1 )
     {
-        return [NSString stringWithFormat:KHLocalizedString(@"value.singular",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return [NSString stringWithFormat:KHLocalizedString(@"value.singular",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     } else {
-        return [NSString stringWithFormat:KHLocalizedString(@"value.plural",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return [NSString stringWithFormat:KHLocalizedString(@"value.plural",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     }
 }
 
@@ -138,9 +153,9 @@ NSString *KHLocalizedString(NSString* ke
 	int test = count == 1;
     if (test)
     {
-        return [NSString stringWithFormat:KHLocalizedString(@"value.singular",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return [NSString stringWithFormat:KHLocalizedString(@"value.singular",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     } else {
-        return [NSString stringWithFormat:KHLocalizedString(@"value.plural",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return [NSString stringWithFormat:KHLocalizedString(@"value.plural",nil), count]; // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     }
 }
 
@@ -154,7 +169,7 @@ NSString *KHLocalizedString(NSString* ke
 		if (someOtherVariable)
         	return KHLocalizedString(@"OK",nil); // no-warning
     } else {
-        return KHLocalizedString(@"value.plural",nil); // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}}
+        return KHLocalizedString(@"value.plural",nil); // expected-warning {{Plural cases are not supported accross all languages. Use a .stringsdict file}} expected-note {{Plural}}
     }
 	return nil;
 }
@@ -221,6 +236,6 @@ NSString *KHLocalizedString(NSString* ke
 
 @implementation MyDebugView
 - (void)setupScreen:(UILabel *)label {
-  label.text = @"Unlocalized";
+  label.text = @"Unlocalized"; // no-warning
 }
 @end




More information about the cfe-commits mailing list