Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -847,6 +847,8 @@ unsigned CommaCount = 0; while (CurrentToken) { if (CurrentToken->is(tok::r_brace)) { + if (Scopes.size() > 1) + Scopes.pop_back(); assert(OpeningBrace.Optional == CurrentToken->Optional); OpeningBrace.MatchingParen = CurrentToken; CurrentToken->MatchingParen = &OpeningBrace; @@ -1146,8 +1148,32 @@ if (Previous && Previous->getType() != TT_DictLiteral) Previous->setType(TT_SelectorName); } - if (!parseBrace()) + switch (Tok->getType()) { + case TT_FunctionLBrace: + case TT_LambdaLBrace: + Scopes.push_back(ScopeType::Function); + break; + case TT_ClassLBrace: + case TT_StructLBrace: + case TT_UnionLBrace: + Scopes.push_back(ScopeType::Class); + break; + case TT_EnumLBrace: + case TT_ControlStatementLBrace: + case TT_ElseLBrace: + case TT_BracedListLBrace: + case TT_CompoundRequirementLBrace: + case TT_ObjCBlockLBrace: + case TT_RecordLBrace: + case TT_RequiresExpressionLBrace: + default: + Scopes.push_back(ScopeType::Other); + } + if (!parseBrace()) { + if (Scopes.size() > 1) + Scopes.pop_back(); return false; + } break; case tok::less: if (parseAngle()) { @@ -1176,6 +1202,8 @@ case tok::r_square: return false; case tok::r_brace: + if (Scopes.size() > 1) + Scopes.pop_back(); // Lines can start with '}'. if (Tok->Previous) return false; @@ -1643,6 +1671,17 @@ } ContextType = Unknown; }; + enum class ScopeType { + // Not contained within scope block + None, + // Contained in class declaration/definition + Class, + // Contained within function definition + Function, + // Contained within other scope block (loop, if/else, etc) + Other, + }; + /// Puts a new \c Context onto the stack \c Contexts for the lifetime /// of each instance. struct ScopedContextCreator { @@ -1895,7 +1934,7 @@ Current.setType(TT_TrailingReturnArrow); } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.setType(determineStarAmpUsage( - Current, + Current, Scopes.back(), Contexts.back().CanBeExpression && Contexts.back().IsExpression, Contexts.back().ContextType == Context::TemplateArgument)); } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret) || @@ -2342,7 +2381,8 @@ } /// Return the type of the given token assuming it is * or &. - TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression, + TokenType determineStarAmpUsage(const FormatToken &Tok, + const ScopeType TokScope, bool IsExpression, bool InTemplateArgument) { if (Style.isJavaScript()) return TT_BinaryOperator; @@ -2446,6 +2486,31 @@ if (IsExpression && !Contexts.back().CaretFound) return TT_BinaryOperator; + // Opeartors at class scope are likely pointer or reference members + if (TokScope == ScopeType::Class) + return TT_PointerOrReference; + + // It's more likely that & represents operator& than an uninitialized + // reference + if (Tok.is(tok::amp) && (PrevToken && PrevToken->Tok.isAnyIdentifier()) && + ((PrevToken->getPreviousNonComment() && + (PrevToken->getPreviousNonComment()->is(tok::amp) || + PrevToken->getPreviousNonComment()->is(tok::period) || + PrevToken->getPreviousNonComment()->is(tok::arrow) || + PrevToken->getPreviousNonComment()->is(tok::arrowstar) || + PrevToken->getPreviousNonComment()->is(tok::periodstar))) || + !PrevToken->getPreviousNonComment()) && + (NextToken && NextToken->Tok.isAnyIdentifier()) && + (NextToken->getNextNonComment() && + (NextToken->getNextNonComment()->is(tok::amp) || + NextToken->getNextNonComment()->is(tok::semi) || + NextToken->getNextNonComment()->is(tok::period) || + NextToken->getNextNonComment()->is(tok::arrow) || + NextToken->getNextNonComment()->is(tok::arrowstar) || + NextToken->getNextNonComment()->is(tok::periodstar)))) { + return TT_BinaryOperator; + } + return TT_PointerOrReference; } @@ -2476,6 +2541,7 @@ } SmallVector Contexts; + static SmallVector Scopes; const FormatStyle &Style; AnnotatedLine &Line; @@ -2722,6 +2788,9 @@ FormatToken *Current; }; +SmallVector AnnotatingParser::Scopes = { + AnnotatingParser::ScopeType::None}; + } // end anonymous namespace void TokenAnnotator::setCommentLineLevels( Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -11267,6 +11267,13 @@ verifyFormat("int operator()(T (&&)[N]) { return 1; }"); verifyFormat("int operator()(T (&)[N]) { return 0; }"); + + verifyFormat("val1 & val2;"); + verifyFormat("val1 & val2 & val3;"); + verifyFormat("class c {\n" + " void func(type &a) { a & member; }\n" + " anotherType &member;\n" + "}"); } TEST_F(FormatTest, UnderstandsAttributes) { Index: clang/unittests/Format/TokenAnnotatorTest.cpp =================================================================== --- clang/unittests/Format/TokenAnnotatorTest.cpp +++ clang/unittests/Format/TokenAnnotatorTest.cpp @@ -175,6 +175,42 @@ ASSERT_EQ(Tokens.size(), 17u) << Tokens; EXPECT_TOKEN(Tokens[9], tok::ampamp, TT_PointerOrReference); EXPECT_TOKEN(Tokens[12], tok::ampamp, TT_PointerOrReference); + + Tokens = annotate("val1 & val2;"); + ASSERT_EQ(Tokens.size(), 5u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::amp, TT_BinaryOperator); + + Tokens = annotate("val1 & val2.member;"); + ASSERT_EQ(Tokens.size(), 7u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::amp, TT_BinaryOperator); + + Tokens = annotate("val1 & val2 & val3;"); + ASSERT_EQ(Tokens.size(), 7u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::amp, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[3], tok::amp, TT_BinaryOperator); + + Tokens = annotate("val1 & val2 // comment\n" + " & val3;"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::amp, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[4], tok::amp, TT_BinaryOperator); + + Tokens = + annotate("val1 & val2.member & val3.member() & val4 & val5->member;"); + ASSERT_EQ(Tokens.size(), 19u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::amp, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[5], tok::amp, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[11], tok::amp, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[13], tok::amp, TT_BinaryOperator); + + Tokens = annotate("class c {\n" + " void func(type &a) { a & member; }\n" + " anotherType &member;\n" + "}"); + ASSERT_EQ(Tokens.size(), 22u) << Tokens; + EXPECT_TOKEN(Tokens[7], tok::amp, TT_PointerOrReference); + EXPECT_TOKEN(Tokens[12], tok::amp, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[17], tok::amp, TT_PointerOrReference); } TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {