Skip to content

Commit 0961bc0

Browse files
fix: Limit the length of strings to inspect (#736)
1 parent 65a38a1 commit 0961bc0

3 files changed

Lines changed: 66 additions & 23 deletions

File tree

Documentation/Diagnostics/PH2080.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212

1313
## Introduction
1414

15-
Avoid hardcoded absolute paths, as they are bound the change without notice.
15+
Avoid hardcoded absolute paths, as they are bound the change without notice. For performance reasons, only the first 259 charcters of a string literal are inspected.
1616

1717
## How to solve
1818

19-
Use configuration instead, for example using `App.config`.
19+
Use configuration instead, for example using `App.config`.
20+
21+
## Remarks
22+
23+
Only Windows absolute or UNC paths are reported. Formatted like: "c:\\temp\example.xml" or "\\server\share\example.xml"
2024

2125
## Example
2226

Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/NoHardCodedPathsAnalyzer.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@ namespace Philips.CodeAnalysis.MaintainabilityAnalyzers.Maintainability
1313
/*
1414
* Analyzer for hardcoded absolute path.
1515
* Reports diagnostics if an absolute path is used,
16-
* For example: c:\users\Bin\example.xml - Windows & /home/kt/abc.sql - Linux
16+
* For example: c:\users\Bin\example.xml
17+
* or: \\server\\share\example.xml
18+
*
19+
* This Analyzer only reports diagnostics on Windows.
1720
*/
1821
[DiagnosticAnalyzer(LanguageNames.CSharp)]
1922
public class NoHardCodedPathsAnalyzer : SingleDiagnosticAnalyzer
2023
{
24+
private const int MaxStringLength = 259;
2125
private const string Title = @"Avoid hardcoded absolute paths";
2226
private const string MessageFormat = Title;
2327
private const string Description = Title;
24-
private readonly Regex WindowsPattern = new(@"^[a-zA-Z]:\\{1,2}(((?![<>:/\\|?*]).)+((?<![ .])\\{1,2})?)*$", RegexOptions.Singleline | RegexOptions.Compiled, TimeSpan.FromSeconds(1));
28+
private readonly Regex _windowsPattern = new(@"^(([a-zA-Z]:)|\\)\\{1,2}(((?![<>:/\\|?*]).)+((?<![ .])\\{1,2})?)*$", RegexOptions.Singleline | RegexOptions.Compiled, TimeSpan.FromSeconds(1));
2529

2630
public NoHardCodedPathsAnalyzer()
2731
: base(DiagnosticId.NoHardcodedPaths, Title, MessageFormat, Description, Categories.Maintainability)
@@ -45,14 +49,20 @@ private void Analyze(SyntaxNodeAnalysisContext context)
4549
return;
4650
}
4751

48-
//if the character of the string do not match either of the characters : for windows and / for linux; no need to run regex, simply return.
49-
if (!pathValue[1].Equals(':') && !pathValue[0].Equals('/'))
52+
// If the character of the string do not match either of the characters : or \\ ; no need to run regex, simply return.
53+
if (!pathValue.Contains(":") && !pathValue.Contains("\\"))
5054
{
5155
return;
5256
}
5357

58+
// Limit to first MAX_PATH characters, to prevent long analysis times.
59+
if (pathValue.Length > MaxStringLength)
60+
{
61+
pathValue = pathValue.Substring(0, MaxStringLength);
62+
}
63+
5464
// If the pattern matches the text value, report the diagnostic.
55-
if (WindowsPattern.IsMatch(pathValue))
65+
if (_windowsPattern.IsMatch(pathValue))
5666
{
5767
Location location = stringLiteralExpressionNode.GetLocation();
5868
var diagnostic = Diagnostic.Create(Rule, location);

Philips.CodeAnalysis.Test/Maintainability/Maintainability/NoHardCodedPathsAnalyzerTest.cs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ protected override DiagnosticAnalyzer GetDiagnosticAnalyzer()
2020

2121
[TestMethod]
2222
[TestCategory(TestDefinitions.UnitTests)]
23-
public async Task CatchesHardCodedAbsoluteWindowsPathsAsync()
23+
public async Task CatchesHardCodedAbsoluteWindowsPaths()
2424
{
2525
const string template = @"
2626
using System;
@@ -33,12 +33,11 @@ public void Test()
3333
}
3434
";
3535
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
36-
3736
}
3837

3938
[TestMethod]
4039
[TestCategory(TestDefinitions.UnitTests)]
41-
public async Task CatchesHardCodedAbsoluteWindowsPathWithDoubleSlashAsync()
40+
public async Task CatchesHardCodedAbsoluteWindowsPathWithDoubleSlash()
4241
{
4342
const string template = @"
4443
using System;
@@ -51,13 +50,12 @@ public void Test()
5150
}
5251
";
5352
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
54-
5553
}
5654

5755

5856
[TestMethod]
5957
[TestCategory(TestDefinitions.UnitTests)]
60-
public async Task CatchesHardCodedPathsRegardlessOfCaseAsync()
58+
public async Task CatchesHardCodedPathsRegardlessOfCase()
6159
{
6260
const string template = @"
6361
using System;
@@ -70,12 +68,28 @@ public void Test()
7068
}
7169
";
7270
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
71+
}
7372

73+
[TestMethod]
74+
[TestCategory(TestDefinitions.UnitTests)]
75+
public async Task CatchesHardCodedPathsAsUnc()
76+
{
77+
const string template = @"
78+
using System;
79+
class Foo
80+
{
81+
public void Test()
82+
{
83+
string path = @""\\server\share\BIN\EXAMPLE.XML"";
84+
}
85+
}
86+
";
87+
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
7488
}
7589

7690
[TestMethod]
7791
[TestCategory(TestDefinitions.UnitTests)]
78-
public async Task CatchesHardCodedPaths2Async()
92+
public async Task CatchesHardCodedPathsAsAbsolute()
7993
{
8094
const string template = @"
8195
using System;
@@ -99,12 +113,11 @@ public void Test()
99113
}
100114
";
101115
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
102-
103116
}
104117

105118
[TestMethod]
106119
[TestCategory(TestDefinitions.UnitTests)]
107-
public async Task CatchesHardCodedPathsWithSpaceAsync()
120+
public async Task CatchesHardCodedPathsWithSpace()
108121
{
109122
const string template = @"
110123
using System;
@@ -118,12 +131,29 @@ public void Test()
118131
";
119132

120133
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
134+
}
135+
136+
[TestMethod]
137+
[TestCategory(TestDefinitions.UnitTests)]
138+
public async Task CatchesHardCodedPathsInLongStringLiterals()
139+
{
140+
const string template = @"
141+
using System;
142+
class Foo
143+
{
144+
public void Test()
145+
{
146+
string path = @""c:\users\test in a veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery long string literal"";
147+
}
148+
}
149+
";
121150

151+
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
122152
}
123153

124154
[TestMethod]
125155
[TestCategory(TestDefinitions.UnitTests)]
126-
public async Task CatchesHardCodedPathsWithSpecialCharactersAsync()
156+
public async Task CatchesHardCodedPathsWithSpecialCharacters()
127157
{
128158
const string template = @"
129159
using System;
@@ -137,13 +167,12 @@ public void Test()
137167
";
138168

139169
await VerifyDiagnostic(template, DiagnosticId.NoHardcodedPaths).ConfigureAwait(false);
140-
141170
}
142171

143172

144173
[TestMethod]
145174
[TestCategory(TestDefinitions.UnitTests)]
146-
public async Task DoesNotCatchNormalStringAsync()
175+
public async Task DoesNotCatchNormalString()
147176
{
148177
const string template = @"
149178
using System;
@@ -162,7 +191,7 @@ public void Test()
162191

163192
[TestMethod]
164193
[TestCategory(TestDefinitions.UnitTests)]
165-
public async Task DoesNotCatchShortStringAsync()
194+
public async Task DoesNotCatchShortString()
166195
{
167196
const string template = @"
168197
using System;
@@ -180,7 +209,7 @@ public void Test()
180209

181210
[TestMethod]
182211
[TestCategory(TestDefinitions.UnitTests)]
183-
public async Task DoesNotCatchEmptyStringAsync()
212+
public async Task DoesNotCatchEmptyString()
184213
{
185214
const string template = @"
186215
using System;
@@ -198,7 +227,7 @@ public void Test()
198227

199228
[TestMethod]
200229
[TestCategory(TestDefinitions.UnitTests)]
201-
public async Task DoesNotCatchRelativePathAsync()
230+
public async Task DoesNotCatchRelativePath()
202231
{
203232
const string template = @"
204233
using system;
@@ -215,7 +244,7 @@ public void test()
215244

216245
[TestMethod]
217246
[TestCategory(TestDefinitions.UnitTests)]
218-
public async Task DoesNotCatchPathsInCommentsAsync()
247+
public async Task DoesNotCatchPathsInComments()
219248
{
220249
const string template = @"
221250
using System;
@@ -236,7 +265,7 @@ public void Test()
236265

237266
[TestMethod]
238267
[TestCategory(TestDefinitions.UnitTests)]
239-
public async Task DoesNotCatchPathsInTestCodeAsync()
268+
public async Task DoesNotCatchPathsInTestCode()
240269
{
241270
const string template = @"
242271
using System;

0 commit comments

Comments
 (0)