Skip to content

Commit eb435cb

Browse files
committed
Direct and camel-cased concatenation fixits for repeated identifiers in function declarations
Additional QoI to also provide a fix-it to concatenate in camel-case. rdar://problem/25761940
1 parent 2118585 commit eb435cb

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ ERROR(keyword_cant_be_identifier,none,
663663
"keyword '%0' cannot be used as an identifier here", (StringRef))
664664
ERROR(repeated_identifier,none,
665665
"found an unexpected second identifier in %0 declaration; is there an accidental break?", (StringRef))
666+
NOTE(join_identifiers,none,
667+
"join the identifiers together", ())
668+
NOTE(join_identifiers_camel_case,none,
669+
"join the identifiers together with camel-case", ())
666670
NOTE(backticks_to_escape,none,
667671
"if this name is unavoidable, use backticks to escape it", ())
668672
ERROR(expected_rparen_tuple_pattern_list,none,

lib/Parse/ParseDecl.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/ParameterList.h"
2626
#include "swift/Basic/Defer.h"
2727
#include "swift/Basic/Fallthrough.h"
28+
#include "swift/Basic/StringExtras.h"
2829
#include "llvm/Support/MemoryBuffer.h"
2930
#include "llvm/Support/Path.h"
3031
#include "llvm/Support/SaveAndRestore.h"
@@ -4463,9 +4464,27 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
44634464
// identifier, it might've been a single identifier that got broken by a
44644465
// space or newline accidentally.
44654466
if (Tok.isIdentifierOrUnderscore() && SimpleName.str().back() != '<') {
4466-
diagnose(Tok.getLoc(), diag::repeated_identifier, "function")
4467-
.fixItReplace(SourceRange(NameLoc, Tok.getLoc()),
4468-
NameTok.getText().str() + Tok.getText().str());
4467+
diagnose(Tok.getLoc(), diag::repeated_identifier, "function");
4468+
4469+
SourceRange DoubleIdentifierRange(NameLoc, Tok.getLoc());
4470+
4471+
// Provide two fix-its: a direct concatentation of the two identifiers
4472+
// and a camel-cased version.
4473+
4474+
auto DirectConcatenation = NameTok.getText().str() + Tok.getText().str();
4475+
4476+
diagnose(Tok.getLoc(), diag::join_identifiers)
4477+
.fixItReplace(DoubleIdentifierRange, DirectConcatenation);
4478+
4479+
SmallString<8> CapitalizedScratch;
4480+
auto Capitalized = camel_case::toSentencecase(Tok.getText(),
4481+
CapitalizedScratch);
4482+
auto CamelCaseConcatenation = NameTok.getText().str() + Capitalized.str();
4483+
4484+
if (DirectConcatenation != CamelCaseConcatenation)
4485+
diagnose(Tok.getLoc(), diag::join_identifiers_camel_case)
4486+
.fixItReplace(DoubleIdentifierRange, CamelCaseConcatenation);
4487+
44694488
consumeToken();
44704489
}
44714490
}

test/Parse/invalid.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,22 @@ let for = 2
9898
// expected-error @-1 {{keyword 'for' cannot be used as an identifier here}}
9999
// expected-note @-2 {{if this name is unavoidable, use backticks to escape it}} {{5-8=`for`}}
100100

101-
func dog cow() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-13=dogcow}}
102-
func friend ship<T>(x: T) {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-17=friendship}}
101+
func dog cow() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}}
102+
// expected-note@-1 {{join the identifiers together}} {{6-13=dogcow}}
103+
// expected-note@-2 {{join the identifiers together with camel-case}} {{6-13=dogCow}}
104+
func cat Mouse() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}}
105+
// expected-note@-1 {{join the identifiers together}} {{6-15=catMouse}}
106+
func friend ship<T>(x: T) {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}}
107+
// expected-note@-1 {{join the identifiers together}} {{6-17=friendship}}
108+
// expected-note@-2 {{join the identifiers together with camel-case}} {{6-17=friendShip}}
103109
func were
104-
wolf() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-5=werewolf}}
110+
wolf() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}}
111+
// expected-note@-1 {{join the identifiers together}} {{6-5=werewolf}}
112+
// expected-note@-2 {{join the identifiers together with camel-case}} {{6-5=wereWolf}}
105113
func hammer
106-
leavings<T>(x: T) {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-9=hammerleavings}}
114+
leavings<T>(x: T) {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}}
115+
// expected-note@-1 {{join the identifiers together}} {{6-9=hammerleavings}}
116+
// expected-note@-2 {{join the identifiers together with camel-case}} {{6-9=hammerLeavings}}
107117

108118
prefix operator % {}
109119
prefix func %<T>(x: T) -> T { return x } // No error expected - the < is considered an identifier but is peeled off by the parser.

0 commit comments

Comments
 (0)