Note
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãµã€ã³ã€ã³ãŸãã¯ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
.NET Compiler Platform SDK ã«ã¯ãC# ãŸã㯠Visual Basic ã³ãŒãã察象ãšããã«ã¹ã¿ã 蚺æ (ã¢ãã©ã€ã¶ãŒ)ãã³ãŒãä¿®æ£ãã³ãŒããªãã¡ã¯ã¿ãªã³ã°ã蚺æãµãã¬ããµãŒãäœæããããã«å¿ èŠãªããŒã«ãçšæãããŠããŸãã ã¢ãã©ã€ã¶ãŒã«ã¯ãã«ãŒã«ã®éåãèªèããã³ãŒããå«ãŸããŠããŸãã ã³ãŒãä¿®æ£ã«ã¯ãéåãä¿®æ£ããã³ãŒããå«ãŸããŠããŸãã å®è£ ããèŠåã¯ãã³ãŒãæ§é ããã³ãŒãã£ã³ã° ã¹ã¿ã€ã«ãååä»ãèŠåãªã©ããããããã®ã«ããããšãã§ããŸãã .NET ã³ã³ãã€ã© ãã©ãããã©ãŒã ã«ã¯ãéçºè ãã³ãŒããèšè¿°ããéã«åæãå®è¡ããããã®ãã¬ãŒã ã¯ãŒã¯ãšãã³ãŒããä¿®æ£ããããã® Visual Studio UI æ©èœ (ãšãã£ã¿ãŒã§ã®æ³¢ç·ã®è¡šç€ºãVisual Studio ãšã©ãŒäžèЧã®èšå®ã"é»ç" ã®ææ¡ã®äœæãæšå¥šãããä¿®æ£ããã°ã©ã ã®è±å¯ãªãã¬ãã¥ãŒã®è¡šç€ºãªã©) ãçšæãããŠããŸãã
ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãRoslyn API ã䜿çšã㊠ã¢ãã©ã€ã¶ãŒ ã®äœæãšä»éãã ã³ãŒãä¿®æ£ ã«ã€ããŠèª¬æããŸãã ã¢ãã©ã€ã¶ãŒã¯ããœãŒã¹ ã³ãŒãåæãå®è¡ããåé¡ããŠãŒã¶ãŒã«å ±åããæ¹æ³ã§ãã å¿
èŠã«å¿ããŠãã³ãŒãä¿®æ£ãã¢ãã©ã€ã¶ãŒã«é¢é£ä»ããŠããŠãŒã¶ãŒã®ãœãŒã¹ ã³ãŒããžã®å€æŽã衚ãããšãã§ããŸãã ãã®ãã¥ãŒããªã¢ã«ã§ã¯ã const 修食åã䜿çšããŠå®£èšã§ããã宣èšã§ããªãããŒã«ã«å€æ°å®£èšãæ€çŽ¢ããã¢ãã©ã€ã¶ãŒãäœæããŸãã ä»å±ã®ã³ãŒãä¿®æ£ã«ããããããã®å®£èšã倿Žããã const 修食åã远å ãããŸãã
[åææ¡ä»¶]
Visual Studio ã€ã³ã¹ããŒã©ãŒã䜿çšã㊠ã.NET Compiler Platform SDK ãã€ã³ã¹ããŒã«ããå¿ èŠããããŸãã
ã€ã³ã¹ããŒã«æé - Visual Studio ã€ã³ã¹ããŒã©ãŒ
Visual Studio ã€ã³ã¹ããŒã©ãŒã§ .NET ã³ã³ãã€ã© ãã©ãããã©ãŒã SDK ãèŠã€ããã«ã¯ã次㮠2 ã€ã®æ¹æ³ããããŸãã
Visual Studio ã€ã³ã¹ããŒã©ãŒ - ã¯ãŒã¯ããŒã ãã¥ãŒã䜿çšããŠã€ã³ã¹ããŒã«ãã
.NET Compiler Platform SDK ã¯ãVisual Studio æ¡åŒµæ©èœéçºã¯ãŒã¯ããŒãã®äžéšãšããŠèªåçã«éžæãããŸããã ãªãã·ã§ã³ã³ã³ããŒãã³ããšããŠéžæããå¿ èŠããããŸãã
- Visual Studio ã€ã³ã¹ããŒã©ãŒãå®è¡ãã
- [倿Ž] ãéžæããŸã
- Visual Studio æ¡åŒµæ©èœã®éçºã¯ãŒã¯ããŒãã確èªããŸãã
- æŠèŠããªãŒã§ Visual Studio æ¡åŒµæ©èœéçº ããŒããéããŸãã
- .NET ã³ã³ãã€ã© ãã©ãããã©ãŒã SDK ã®ããã¯ã¹ããªã³ã«ãªã£ãŠããããšã確èªããŸãã
- [倿Ž] ãéžæããŸãã
å¿ èŠã«å¿ããŠã DGML ãšãã£ã¿ãŒ ã§ããžã¥ã¢ã©ã€ã¶ãŒã«ã°ã©ãã衚瀺ããããšãã§ããŸãã
- æŠèŠããªãŒã§ [ åã ã®ã³ã³ããŒãã³ã ] ããŒããéããŸãã
- DGML ãšãã£ã¿ãŒã®ãã§ã㯠ããã¯ã¹ããªã³ã«ããŸã
Visual Studio ã€ã³ã¹ããŒã©ãŒã䜿çšããã€ã³ã¹ããŒã« - [åã ã®ã³ã³ããŒãã³ã] ã¿ã
- Visual Studio ã€ã³ã¹ããŒã©ãŒãå®è¡ãã
- [倿Ž] ãéžæããŸã
- [ åã ã®ã³ã³ããŒãã³ã ] ã¿ããéžæãã
- .NET ã³ã³ãã€ã© ãã©ãããã©ãŒã SDK ã®ãã§ã㯠ããã¯ã¹ããªã³ã«ããŸãã äžéšã® [ ã³ã³ãã€ã©ããã«ã ããŒã«ãããã³ã©ã³ã¿ã€ã ] ã»ã¯ã·ã§ã³ã«ãããŸãã
- [倿Ž] ãéžæããŸãã
å¿ èŠã«å¿ããŠã DGML ãšãã£ã¿ãŒ ã§ããžã¥ã¢ã©ã€ã¶ãŒã«ã°ã©ãã衚瀺ããããšãã§ããŸãã
- DGML ãšãã£ã¿ãŒã®ãã§ã㯠ããã¯ã¹ããªã³ã«ããŸãã [ ã³ãŒã ããŒã« ] ã»ã¯ã·ã§ã³ã«è¡šç€ºãããŸãã
ã¢ãã©ã€ã¶ãŒã®äœæãšæ€èšŒã«ã¯ãããã€ãã®æé ãå«ãŸããŸãã
- ãœãªã¥ãŒã·ã§ã³ãäœæããŸãã
- ã¢ãã©ã€ã¶ãŒã®ååãšèª¬æãç»é²ããŸãã
- ã¬ããŒãè§£æã®èŠåããã³æšå¥šäºé ã
- æšå¥šäºé ãåãå ¥ããã³ãŒãä¿®æ£ãå®è£ ããŸãã
- åäœãã¹ãã䜿çšããŠåæãæ¹åããŸãã
ãœãªã¥ãŒã·ã§ã³ãäœæãã
- Visual Studio ã§ã[ ãã¡ã€ã«>æ°èŠäœæ>ãããžã§ã¯ã/ãœãªã¥ãŒã·ã§ã³ ] ãéžæããŠã[æ°ãããããžã§ã¯ã] ãã€ã¢ãã°ãéããŸãã
- æ€çŽ¢ããã¯ã¹ã«ã Analyzer ããšå ¥åããŠã ã³ãŒãä¿®æ£ä»ãã¢ãã©ã€ã¶ãŒ (.NET Standard) ãã³ãã¬ãŒããèŠã€ããŸãã
- 次ãžãéžæããŸãã
- ãããžã§ã¯ãã« "MakeConst" ãšããååãä»ãã[ äœæ] ãéžæããŸãã
泚
ã³ã³ãã€ã« ãšã©ãŒãçºçããå¯èœæ§ããããŸã (MSB4062: "CompareBuildTaskVersion" ã¿ã¹ã¯ãèªã¿èŸŒããŸããã§ãã)ã ãã®ãšã©ãŒã解決ããã«ã¯ãNuGet ããã±ãŒãž ãããŒãžã£ãŒã䜿çšããŠãœãªã¥ãŒã·ã§ã³å
ã® NuGet ããã±ãŒãžãæŽæ°ããããããã±ãŒãž ãããŒãžã£ãŒ ã³ã³ãœãŒã« ãŠã£ã³ããŠã§ Update-Package ã䜿çšããŸãã
ã¢ãã©ã€ã¶ãŒ ãã³ãã¬ãŒãã調ã¹ã
ã³ãŒãä¿®æ£ãã³ãã¬ãŒããå«ãã¢ãã©ã€ã¶ãŒã¯ã次㮠5 ã€ã®ãããžã§ã¯ããäœæããŸãã
- MakeConstãã¢ãã©ã€ã¶ãŒãå«ã¿ãŸãã
- ã³ãŒãä¿®æ£ãå«ã MakeConst.CodeFixesã
- MakeConst.Packageãã¢ãã©ã€ã¶ãŒãšã³ãŒãä¿®æ£ã®ããã® NuGet ããã±ãŒãžãçæããããã«äœ¿çšãããŸãã
- MakeConst.Testãããã¯åäœãã¹ã ãããžã§ã¯ãã§ãã
- MakeConst.Vsixãããã¯ãæ°ããã¢ãã©ã€ã¶ãŒãèªã¿èŸŒãã Visual Studio ã® 2 çªç®ã®ã€ã³ã¹ã¿ã³ã¹ãèµ·åããæ¢å®ã®ã¹ã¿ãŒãã¢ãã ãããžã§ã¯ãã§ãã F5 ããŒãæŒã㊠VSIX ãããžã§ã¯ããéå§ããŸãã
泚
ã¢ãã©ã€ã¶ãŒã¯.NET Core ç°å¢ (ã³ãã³ã ã©ã€ã³ ãã«ã) ãš .NET Framework ç°å¢ (Visual Studio) ã§å®è¡ã§ããããã.NET Standard 2.0 ãã¿ãŒã²ããã«ããå¿ èŠããããŸãã
ãã³ã
ã¢ãã©ã€ã¶ãŒãå®è¡ãããšãVisual Studio ã® 2 ã€ç®ã®ã³ããŒãéå§ãããŸãã ãã® 2 çªç®ã®ã³ããŒã§ã¯ãå¥ã®ã¬ãžã¹ã㪠ãã€ãã䜿çšããŠèšå®ãæ ŒçŽããŸãã ãã®éãã«ãããVisual Studio ã® 2 ã€ã®ã³ããŒã§ããžã¥ã¢ã«èšå®ãåºå¥ã§ããŸãã Visual Studio ã®å®éšçšã®å®è¡ã«å¥ã®ããŒããéžæã§ããŸãã ãŸããVisual Studio ã®è©Šéšçãªå®è¡ã䜿çšããŠãèšå®ãããŒãã³ã°ããããVisual Studio ã¢ã«ãŠã³ãã«ãµã€ã³ã€ã³ãããããªãã§ãã ããã èšå®ã¯å€ãç¶ããŸãã
ãã€ãã«ã¯ãéçºäžã®ã¢ãã©ã€ã¶ãŒã ãã§ãªãã以åã«éããã¢ãã©ã€ã¶ãŒãå«ãŸããŸãã Roslyn ãã€ãããªã»ããããã«ã¯ãæåã§ %LocalAppData%\Microsoft\VisualStudio ããåé€ããå¿
èŠããããŸãã Roslyn ãã€ãã®ãã©ã«ããŒåã¯ãRoslynãªã©ã16.0_9ae182f9Roslynã§çµãããŸãã Hive ãåé€ããåŸããœãªã¥ãŒã·ã§ã³ãã¯ãªãŒã³ã¢ããããŠåæ§ç¯ããããšãå¿
èŠã«ãªãå ŽåããããŸãã
å ã»ã©éå§ãã 2 çªç®ã® Visual Studio ã€ã³ã¹ã¿ã³ã¹ã§ãæ°ãã C# ã³ã³ãœãŒã« ã¢ããªã±ãŒã·ã§ã³ ãããžã§ã¯ããäœæããŸã (ãã¹ãŠã®ã¿ãŒã²ãã ãã¬ãŒã ã¯ãŒã¯ãæ©èœããŸããã¢ãã©ã€ã¶ãŒã¯ãœãŒã¹ ã¬ãã«ã§åäœããŸã)ãæ³¢ç·ã®äžç·ãä»ããããŒã¯ã³ã«ã«ãŒãœã«ãåããããšãã¢ãã©ã€ã¶ãŒã«ãã£ãŠæäŸãããèŠåããã¹ãã衚瀺ãããŸãã
ãã³ãã¬ãŒãã¯ã次ã®å³ã«ç€ºãããã«ãååã«å°æåãå«ãŸããŠããåå宣èšã«å¯ŸããèŠåãå ±åããã¢ãã©ã€ã¶ãŒãäœæããŸãã
ãã®ãã³ãã¬ãŒãã«ã¯ãå°æåãå«ããã¹ãŠã®ååããã¹ãŠã®å€§æåã«å€æŽããã³ãŒãä¿®æ£ãçšæãããŠããŸãã èŠåãšå ±ã«è¡šç€ºãããé»çãéžæãããšãæšå¥šããã倿Žã確èªã§ããŸãã æšå¥šããã倿Žãåãå ¥ãããšããœãªã¥ãŒã·ã§ã³å ã®ååãšããã®åãžã®ãã¹ãŠã®åç §ãæŽæ°ãããŸãã åæã¢ãã©ã€ã¶ãŒã®åäœã確èªããããã2 ã€ç®ã® Visual Studio ã€ã³ã¹ã¿ã³ã¹ãéããŠãã¢ãã©ã€ã¶ãŒ ãããžã§ã¯ãã«æ»ããŸãã
Visual Studio ã® 2 ã€ç®ã®ã³ããŒãéå§ããã¢ãã©ã€ã¶ãŒå
ã®ãã¹ãŠã®å€æŽããã¹ãããæ°ããã³ãŒããäœæããå¿
èŠã¯ãããŸããã ãã®ãã³ãã¬ãŒãã§ã¯ãåäœãã¹ã ãããžã§ã¯ããèªåçã«äœæãããŸãã ãã®ãããžã§ã¯ãã«ã¯ 2 ã€ã®ãã¹ããå«ãŸããŠããŸãã
TestMethod1 ã¯ã蚺æãããªã¬ãŒããã«ã³ãŒããåæãããã¹ãã®äžè¬çãªåœ¢åŒã瀺ããŠããŸãã
TestMethod2 ã¯ã蚺æãããªã¬ãŒãããã¹ãã®åœ¢åŒã瀺ããæšå¥šãããã³ãŒãä¿®æ£ããã°ã©ã ãé©çšããŸãã ã¢ãã©ã€ã¶ãŒãšã³ãŒãä¿®æ£ããã«ããããšãã«ãããŸããŸãªã³ãŒãæ§é ã®ãã¹ããèšè¿°ããŠäœæ¥ãæ€èšŒããŸãã ã¢ãã©ã€ã¶ãŒã®åäœãã¹ãã¯ãVisual Studio ã䜿çšããŠå¯Ÿè©±åœ¢åŒã§ãã¹ããããããã¯ããã«é«éã§ãã
ãã³ã
ã¢ãã©ã€ã¶ãŒã®åäœãã¹ãã¯ãã¢ãã©ã€ã¶ãŒãããªã¬ãŒããå¿ èŠããããããªã¬ãŒãã¹ãã§ãªãã³ãŒãã³ã³ã¹ãã©ã¯ããææ¡ããŠããå Žåã«æé©ãªããŒã«ã§ãã Visual Studio ã®å¥ã®ã³ããŒã«ã¢ãã©ã€ã¶ãŒãèªã¿èŸŒãã®ã¯ããŸã èããããŠããªãå¯èœæ§ã®ããã³ã³ã¹ãã©ã¯ããæ¢çŽ¢ããŠèŠã€ããããã®åªããããŒã«ã§ãã
ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãããŒã«ã«å®æ°ã«å€æã§ããããŒã«ã«å€æ°å®£èšããŠãŒã¶ãŒã«å ±åããã¢ãã©ã€ã¶ãŒãèšè¿°ããŸãã ããšãã°ã次ã®ã³ãŒããèããŠã¿ãŸãããã
int x = 0;
Console.WriteLine(x);
åã®ã³ãŒãã§ã¯ã x ã«ã¯å®æ°å€ãå²ãåœãŠããã倿Žãããããšã¯ãããŸããã
const修食åã䜿çšããŠå®£èšã§ããŸãã
const int x = 0;
Console.WriteLine(x);
倿°ã宿°ã«ã§ãããã©ããã倿ããããã®åæãå¿ èŠã§ãããæ§æåæãåæåååŒã®å®æ°åæãããã³å€æ°ãæžã蟌ãŸããªãããã«ããããã®ããŒã¿ãããŒåæãå¿ èŠã§ãã .NET ã³ã³ãã€ã© ãã©ãããã©ãŒã ã«ã¯ããã®åæãç°¡åã«å®è¡ã§ãã API ãçšæãããŠããŸãã
ã¢ãã©ã€ã¶ãŒç»é²ãèšå®ãã
ãã³ãã¬ãŒãã¯ãMakeConstAnalyzer.cs ãã¡ã€ã«ã«åæDiagnosticAnalyzer ã¯ã©ã¹ãäœæããŸãã ãã®åæã¢ãã©ã€ã¶ãŒã¯ããã¹ãŠã®ã¢ãã©ã€ã¶ãŒã® 2 ã€ã®éèŠãªããããã£ã瀺ããŠããŸãã
- ãã¹ãŠã®èšºæã¢ãã©ã€ã¶ãŒã¯ããããåäœããèšèªãèšè¿°ãã
[DiagnosticAnalyzer]屿§ãæäŸããå¿ èŠããããŸãã - ãã¹ãŠã®èšºæã¢ãã©ã€ã¶ãŒã¯ã DiagnosticAnalyzer ã¯ã©ã¹ããçŽæ¥ãŸãã¯éæ¥çã«æŽŸçããå¿ èŠããããŸãã
ãã³ãã¬ãŒãã«ã¯ãã¢ãã©ã€ã¶ãŒã®äžéšã§ããåºæ¬çãªæ©èœã衚瀺ãããŸãã
- ã¢ã¯ã·ã§ã³ãç»é²ããŸãã ã¢ã¯ã·ã§ã³ã¯ãã¢ãã©ã€ã¶ãŒãããªã¬ãŒããŠã³ãŒãã«éåããªãã調ã¹ãå¿ èŠãããã³ãŒã倿Žã衚ããŸãã Visual Studio ã¯ãç»é²ãããã¢ã¯ã·ã§ã³ã«äžèŽããã³ãŒãç·šéãæ€åºãããšãã¢ãã©ã€ã¶ãŒã®ç»é²æžã¿ã¡ãœãããåŒã³åºããŸãã
- 蚺æãäœæããŸãã ã¢ãã©ã€ã¶ãŒã¯ãéåãæ€åºãããšãVisual Studio ãéåããŠãŒã¶ãŒã«éç¥ããããã«äœ¿çšãã蚺æãªããžã§ã¯ããäœæããŸãã
ã¢ã¯ã·ã§ã³ã¯ã DiagnosticAnalyzer.Initialize(AnalysisContext) ã¡ãœããã®ãªãŒããŒã©ã€ãã«ç»é²ããŸãã ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãããŒã«ã«å®£èšãæ€çŽ¢ãã æ§æããŒã ã«ã¢ã¯ã»ã¹ãã宿°å€ãæã€æ§æããŒãã確èªããŸãã 宣èšã宿°ã®å Žåã¯ãã¢ãã©ã€ã¶ãŒã«ãã£ãŠèšºæãäœæãããå ±åãããŸãã
æåã®æé ã§ã¯ãç»é²å®æ°ãš Initialize ã¡ãœãããæŽæ°ããŠããããã®å®æ°ã "Make Const" ã¢ãã©ã€ã¶ãŒã瀺ãããã«ããŸãã ã»ãšãã©ã®æåå宿°ã¯ãæååãªãœãŒã¹ ãã¡ã€ã«ã§å®çŸ©ãããŠããŸãã ããŒã«ã©ã€ãºã容æã«ããããã«ããã®ãã©ã¯ãã£ã¹ã«åŸã£ãŠãã ããã
MakeConst ã¢ãã©ã€ã¶ãŒ ãããžã§ã¯ãã® Resources.resx ãã¡ã€ã«ãéããŸãã ãã®ã¢ã¯ã·ã§ã³ã«ããããªãœãŒã¹ ãšãã£ã¿ãŒã衚瀺ãããŸãã æååãªãœãŒã¹ã次ã®ããã«æŽæ°ããŸãã
-
AnalyzerDescriptionã "Variables that aren't modified should be made constants." ã«å€æŽããŸãã -
AnalyzerMessageFormatã "Variable '{0}' can be made constant" ã«å€æŽããŸãã -
AnalyzerTitleã "Variable can be made constant" ã«å€æŽããŸãã
å®äºãããšã次ã®å³ã«ç€ºãããã«ãªãœãŒã¹ ãšãã£ã¿ãŒã衚瀺ãããŸãã
ã¢ãã©ã€ã¶ãŒ ãã¡ã€ã«ã®æ®ãã®å€æŽãè¡ããŸãã Visual Studio ã§ MakeConstAnalyzer.cs ãéããŸãã ç»é²ãããã¢ã¯ã·ã§ã³ããã·ã³ãã«ã«å¯ŸããŠåäœããã¢ã¯ã·ã§ã³ããæ§æã«äœçšããã¢ã¯ã·ã§ã³ã«å€æŽããŸãã
MakeConstAnalyzerAnalyzer.Initializeã¡ãœããã§ãã·ã³ãã«ã«å¯Ÿããã¢ã¯ã·ã§ã³ãç»é²ããè¡ãèŠã€ããŸãã
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
次ã®è¡ã«çœ®ãæããŸãã
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.LocalDeclarationStatement);
ãã®å€æŽåŸã AnalyzeSymbol ã¡ãœãããåé€ã§ããŸãã ãã®ã¢ãã©ã€ã¶ãŒã¯ãSyntaxKind.LocalDeclarationStatementã¹ããŒãã¡ã³ãã§ã¯ãªããSymbolKind.NamedTypeã調ã¹ãŸãã
AnalyzeNode ã«èµ€ãæ³¢ç·ã衚瀺ãããŠããããšã«æ³šæããŠãã ããã å
ã»ã©è¿œå ããã³ãŒãã¯ã宣èšãããŠããªã AnalyzeNode ã¡ãœãããåç
§ããŸãã æ¬¡ã®ã³ãŒãã䜿çšããŠããã®ã¡ãœããã宣èšããŸãã
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
}
次ã®ã³ãŒãã«ç€ºãããã«ãMakeConstAnalyzer.csã§Categoryã "Usage" ã«å€æŽããŸãã
private const string Category = "Usage";
const ã«ãªãå¯èœæ§ãããããŒã«ã«å®£èšãèŠã€ãã
ããã§ã AnalyzeNode ã¡ãœããã®æåã®ããŒãžã§ã³ãèšè¿°ããæºåãã§ããŸããã æ¬¡ã®ã³ãŒãã®ããã«ã const ã§ãããããã§ã¯ãªã 1 ã€ã®ããŒã«ã«å®£èšãæ¢ãå¿
èŠããããŸãã
int x = 0;
Console.WriteLine(x);
æåã®æé ã¯ãããŒã«ã«å®£èšãèŠã€ããããšã§ãã MakeConstAnalyzer.csã® AnalyzeNode ã«æ¬¡ã®ã³ãŒã ã远å ããŸãã
var localDeclaration = (LocalDeclarationStatementSyntax)context.Node;
ã¢ãã©ã€ã¶ãŒã«ããŒã«ã«å®£èš (ããŒã«ã«å®£èšã®ã¿) ã®å€æŽãç»é²ãããŠããããããã®ãã£ã¹ãã¯åžžã«æåããŸãã
AnalyzeNode ã¡ãœããã®åŒã³åºããããªã¬ãŒããããŒãã®çš®é¡ãä»ã«ãããŸããã æ¬¡ã«ã const 修食åã®å®£èšã確èªããŸãã èŠã€ããå Žåã¯ãããã«æ»ããŸãã æ¬¡ã®ã³ãŒãã¯ãããŒã«ã«å®£èšã§ const 修食åãæ€çŽ¢ããŸãã
// make sure the declaration isn't already const:
if (localDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword))
{
return;
}
æåŸã«ã倿°ã constã§ããããšã確èªããå¿
èŠããããŸãã ãã®ãã§ãã¯ã«ãããåæååŸã«å€æ°ãå²ãåœãŠãããªãããã«ããŸãã
SyntaxNodeAnalysisContextã䜿çšããŠãã»ãã³ãã£ãã¯åæãå®è¡ããŸãã
contextåŒæ°ã䜿çšããŠãããŒã«ã«å€æ°å®£èšãconstã§ãããã©ããã倿ããŸãã
Microsoft.CodeAnalysis.SemanticModelã¯ã1 ã€ã®ãœãŒã¹ ãã¡ã€ã«å
ã®ãã¹ãŠã®ã»ãã³ãã£ãã¯æ
å ±ã衚ããŸãã
ã»ãã³ãã£ã㯠ã¢ãã«ã«ã€ããŠè©³ããã¯ããã®èšäºãã芧ãã ããã
Microsoft.CodeAnalysis.SemanticModelã䜿çšããŠãããŒã«ã«å®£èšã¹ããŒãã¡ã³ãã§ããŒã¿ ãããŒåæãå®è¡ããŸãã æ¬¡ã«ããã®ããŒã¿ ãããŒåæã®çµæã䜿çšããŠãããŒã«ã«å€æ°ãä»ã®å Žæã«æ°ããå€ã§æžã蟌ãŸããªãããã«ããŸãã
GetDeclaredSymbolæ¡åŒµã¡ã³ããŒãåŒã³åºããŠå€æ°ã®ILocalSymbolãååŸããããŒã¿ ãããŒåæã®DataFlowAnalysis.WrittenOutside ã³ã¬ã¯ã·ã§ã³å
ã«å«ãŸããŠããªãããšã確èªããŸãã
AnalyzeNode ã¡ãœããã®æ«å°Ÿã«æ¬¡ã®ã³ãŒãã远å ããŸãã
// Perform data flow analysis on the local declaration.
DataFlowAnalysis dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(localDeclaration);
// Retrieve the local symbol for each variable in the local declaration
// and ensure that it is not written outside of the data flow analysis region.
VariableDeclaratorSyntax variable = localDeclaration.Declaration.Variables.Single();
ISymbol variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
远å ããã³ãŒãã¯ã倿°ã倿ŽãããŠããªãããšãä¿èšŒããããã constã§ããŸãã ããã§ã¯èšºæãåŒã³åºããŠã¿ãŸãããã æ¬¡ã®ã³ãŒãã AnalyzeNodeã®æåŸã®è¡ãšããŠè¿œå ããŸãã
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation(), localDeclaration.Declaration.Variables.First().Identifier.ValueText));
F5 ããŒãæŒããŠã¢ãã©ã€ã¶ãŒãå®è¡ããããšã§ãé²è¡ç¶æ³ã確èªã§ããŸãã åã«äœæããã³ã³ãœãŒã« ã¢ããªã±ãŒã·ã§ã³ãèªã¿èŸŒã¿ã次ã®ãã¹ã ã³ãŒãã远å ã§ããŸãã
int x = 0;
Console.WriteLine(x);
é»çã衚瀺ãããã¢ãã©ã€ã¶ãŒã蚺æãå ±åããå¿ èŠããããŸãã ãã ããVisual Studio ã®ããŒãžã§ã³ã«ãã£ãŠã¯ã次ã®ããããã衚瀺ãããŸãã
- é»çããã³ãã¬ãŒãã§çæãããã³ãŒãä¿®æ£ãåŒãç¶ã䜿çšãããŠããã倧æåã«ã§ããããšãããããŸãã
- ãšãã£ã¿ãŒã®äžéšã«ã"MakeConstCodeFixProvider" ã§ãšã©ãŒãçºçããç¡å¹ã«ãªã£ãŠããããšã瀺ããã㌠ã¡ãã»ãŒãžã衚瀺ãããŸãã ãã®ãšã©ãŒã¯ãã³ãŒãä¿®æ£ãããã€ããŒããŸã 倿ŽãããŠãããã
TypeDeclarationSyntaxèŠçŽ ã®ä»£ããã«LocalDeclarationStatementSyntaxèŠçŽ ãèŠã€ããããšãæåŸ ããŠããããã«çºçããŸãã
次ã®ã»ã¯ã·ã§ã³ã§ã¯ãã³ãŒãä¿®æ£ãèšè¿°ããæ¹æ³ã«ã€ããŠèª¬æããŸãã
ã³ãŒãä¿®æ£ãèšè¿°ãã
ã¢ãã©ã€ã¶ãŒã¯ã1 ã€ä»¥äžã®ã³ãŒãä¿®æ£ããã°ã©ã ãæäŸã§ããŸãã ã³ãŒãä¿®æ£ã¯ãå ±åãããåé¡ã«å¯ŸåŠããç·šéãå®çŸ©ããŸãã äœæããã¢ãã©ã€ã¶ãŒã«å¯ŸããŠãconst ããŒã¯ãŒããæ¿å ¥ããã³ãŒãä¿®æ£ãæäŸã§ããŸãã
- int x = 0;
+ const int x = 0;
Console.WriteLine(x);
ãŠãŒã¶ãŒã¯ãšãã£ã¿ãŒã®é»ç UI ããéžæããVisual Studio ã«ãã£ãŠã³ãŒãã倿ŽãããŸãã
CodeFixResources.resx ãã¡ã€ã«ãéããCodeFixTitleã "Make constant" ã«å€æŽããŸãã
ãã³ãã¬ãŒãã«ãã£ãŠè¿œå ããã MakeConstCodeFixProvider.cs ãã¡ã€ã«ãéããŸãã ãã®ã³ãŒãä¿®æ£ã¯ã蚺æã¢ãã©ã€ã¶ãŒã«ãã£ãŠçæããã蚺æ ID ã«æ¢ã«æ¥ç¶ãããŠããŸãããé©åãªã³ãŒã倿ã¯ãŸã å®è£ ãããŠããŸããã
次ã«ã MakeUppercaseAsync ã¡ãœãããåé€ããŸãã é©çšãããªããªããŸããã
ãã¹ãŠã®ã³ãŒãä¿®æ£ãããã€ããŒã¯ã CodeFixProviderããæŽŸçããŸãã ãããã¯ãã¹ãŠ CodeFixProvider.RegisterCodeFixesAsync(CodeFixContext) ããªãŒããŒã©ã€ãããŠã䜿çšå¯èœãªã³ãŒãä¿®æ£ãå ±åããŸãã
RegisterCodeFixesAsyncã§ãæ€çŽ¢ããå
ç¥ããŒãã®çš®é¡ãã蚺æã«åãããŠLocalDeclarationStatementSyntaxã«å€æŽããŸãã
var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<LocalDeclarationStatementSyntax>().First();
次ã«ãæåŸã®è¡ã倿ŽããŠã³ãŒãä¿®æ£ãç»é²ããŸãã ä¿®æ£ã«ããã const 修食åãæ¢åã®å®£èšã«è¿œå ããçµæã®æ°ããããã¥ã¡ã³ããäœæãããŸãã
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create(
title: CodeFixResources.CodeFixTitle,
createChangedDocument: c => MakeConstAsync(context.Document, declaration, c),
equivalenceKey: nameof(CodeFixResources.CodeFixTitle)),
diagnostic);
ã·ã³ãã« MakeConstAsync ã«è¿œå ããã³ãŒãã«ãèµ€ãæ³¢ç·ã衚瀺ãããŠããç¹ã«æ³šç®ããŠãã ããã æ¬¡ã®ã³ãŒãã®ããã«ã MakeConstAsync ã®å®£èšã远å ããŸãã
private static async Task<Document> MakeConstAsync(Document document,
LocalDeclarationStatementSyntax localDeclaration,
CancellationToken cancellationToken)
{
}
æ°ããMakeConstAsync ã¡ãœããã¯ããŠãŒã¶ãŒã®ãœãŒã¹ ãã¡ã€ã«ã衚ãDocumentããDocument宣èšãå«ãæ°ããconstã«å€æããŸãã
宣èšã¹ããŒãã¡ã³ãã®å
é ã«æ¿å
¥ããæ°ãã const ããŒã¯ãŒã ããŒã¯ã³ãäœæããŸãã æåã«å®£èšã¹ããŒãã¡ã³ãã®æåã®ããŒã¯ã³ããå
é ã®ããªãã¢ãåé€ãã const ããŒã¯ã³ã«ã¢ã¿ããããããã«æ³šæããŠãã ããã
MakeConstAsync ã¡ãœããã«æ¬¡ã®ã³ãŒãã远å ããŸãã
// Remove the leading trivia from the local declaration.
SyntaxToken firstToken = localDeclaration.GetFirstToken();
SyntaxTriviaList leadingTrivia = firstToken.LeadingTrivia;
LocalDeclarationStatementSyntax trimmedLocal = localDeclaration.ReplaceToken(
firstToken, firstToken.WithLeadingTrivia(SyntaxTriviaList.Empty));
// Create a const token with the leading trivia.
SyntaxToken constToken = SyntaxFactory.Token(leadingTrivia, SyntaxKind.ConstKeyword, SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker));
次ã«ã次ã®ã³ãŒãã䜿çšããŠã const ããŒã¯ã³ã宣èšã«è¿œå ããŸãã
// Insert the const token into the modifiers list, creating a new modifiers list.
SyntaxTokenList newModifiers = trimmedLocal.Modifiers.Insert(0, constToken);
// Produce the new local declaration.
LocalDeclarationStatementSyntax newLocal = trimmedLocal
.WithModifiers(newModifiers)
.WithDeclaration(localDeclaration.Declaration);
次ã«ãC# ã®æžåŒèšå®èŠåã«äžèŽããããã«æ°ãã宣èšãæžåŒèšå®ããŸãã æ¢åã®ã³ãŒãã«åãããŠå€æŽãæžåŒèšå®ãããšããšã¯ã¹ããªãšã³ã¹ãåäžããŸãã æ¢åã®ã³ãŒãã®çŽåŸã«æ¬¡ã®ã¹ããŒãã¡ã³ãã远å ããŸãã
// Add an annotation to format the new local declaration.
LocalDeclarationStatementSyntax formattedLocal = newLocal.WithAdditionalAnnotations(Formatter.Annotation);
ãã®ã³ãŒãã«ã¯æ°ããåå空éãå¿
èŠã§ãã æ¬¡ã® using ãã£ã¬ã¯ãã£ãããã¡ã€ã«ã®å
é ã«è¿œå ããŸãã
using Microsoft.CodeAnalysis.Formatting;
æåŸã®æé ã§ã¯ãç·šéãè¡ããŸãã ãã®ããã»ã¹ã«ã¯ã次㮠3 ã€ã®æé ããããŸãã
- æ¢åã®ããã¥ã¡ã³ããžã®ãã³ãã«ãååŸããŸãã
- æ¢åã®å®£èšãæ°ãã宣èšã«çœ®ãæããŠãæ°ããããã¥ã¡ã³ããäœæããŸãã
- æ°ããããã¥ã¡ã³ããè¿ããŸãã
MakeConstAsync ã¡ãœããã®æ«å°Ÿã«æ¬¡ã®ã³ãŒãã远å ããŸãã
// Replace the old local declaration with the new local declaration.
SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
SyntaxNode newRoot = oldRoot.ReplaceNode(localDeclaration, formattedLocal);
// Return document with transformed tree.
return document.WithSyntaxRoot(newRoot);
ã³ãŒãä¿®æ£ã詊ããæºåãæŽããŸããã F5 ããŒãæŒããŠãVisual Studio ã® 2 çªç®ã®ã€ã³ã¹ã¿ã³ã¹ã§ã¢ãã©ã€ã¶ãŒ ãããžã§ã¯ããå®è¡ããŸãã 2 çªç®ã® Visual Studio ã€ã³ã¹ã¿ã³ã¹ã§ãæ°ãã C# ã³ã³ãœãŒã« ã¢ããªã±ãŒã·ã§ã³ ãããžã§ã¯ããäœæãã宿°å€ã§åæåãããããŒã«ã«å€æ°å®£èšãããã€ã Main ã¡ãœããã«è¿œå ããŸãã æ¬¡ã®å³ã«ç€ºãããã«ãèŠåãšããŠå ±åãããŠããããšãããããŸãã
ããªãã¯å€ãã®é²æ©ãéããã
const ã«ããããšãã§ãã宣èšã«ã¯ãæ³¢ç·ã衚瀺ãããŠããŸãã ãããããŸã ããäœæ¥ããããŸãã ããã¯ãconstãiãæåŸã«jã§å§ãŸã宣èšã«kã远å ããå Žåã«åé¡ãªãåäœããŸãã ãã ããconst修食åãå¥ã®é åºã§è¿œå ãããšãk以éãã¢ãã©ã€ã¶ãŒã«ãã£ãŠãšã©ãŒãäœæãããŸããkãšconstã®äž¡æ¹ãæ¢ã«iãããŠããªãéããjã¯const宣èšã§ããŸããã 倿°ã宣èšããã³åæåããããŸããŸãªæ¹æ³ã確å®ã«åŠçããã«ã¯ãããã«åæãè¡ãå¿
èŠããããŸãã
åäœãã¹ãããã«ããã
ã¢ãã©ã€ã¶ãŒãšã³ãŒãä¿®æ£ã¯ãconst ãäœæã§ãã 1 ã€ã®å®£èšã®åçŽãªã±ãŒã¹ã§åäœããŸãã ãã®å®è£ ãééããç¯ãå¯èœæ§ã®ãã宣èšã¹ããŒãã¡ã³ãã倿°ååšããŸãã ãããã®ã±ãŒã¹ã«å¯ŸåŠããããã«ããã³ãã¬ãŒãã«ãã£ãŠèšè¿°ãããåäœãã¹ã ã©ã€ãã©ãªã䜿çšããŸãã Visual Studio ã® 2 çªç®ã®ã³ããŒãç¹°ãè¿ãéããããã¯ããã«é«éã§ãã
åäœãã¹ã ãããžã§ã¯ãã§ MakeConstUnitTests.cs ãã¡ã€ã«ãéããŸãã ãã³ãã¬ãŒãã¯ãã¢ãã©ã€ã¶ãŒãšã³ãŒãä¿®æ£åäœãã¹ãã® 2 ã€ã®äžè¬çãªãã¿ãŒã³ã«åŸã 2 ã€ã®ãã¹ããäœæããŸããã
TestMethod1 ã¯ããã¹ãã®ãã¿ãŒã³ã瀺ããŠããŸãããããã¹ãã§ã¯ãªããšãã«ã¢ãã©ã€ã¶ãŒã蚺æãå ±åããªãããã«ããŸãã
TestMethod2 ã¯ã蚺æãå ±åããã³ãŒãä¿®æ£ãå®è¡ããããã®ãã¿ãŒã³ã瀺ããŠããŸãã
ãã®ãã³ãã¬ãŒãã§ã¯ãåäœãã¹ã ã« Microsoft.CodeAnalysis.Testing ããã±ãŒãžã䜿çšããŸãã
ãã³ã
ãã¹ã ã©ã€ãã©ãªã§ã¯ã次ã®ãããªç¹æ®ãªããŒã¯ã¢ããæ§æããµããŒããããŠããŸãã
-
[|text|]:textã®èšºæãå ±åãããããšã瀺ããŸãã æ¢å®ã§ã¯ããã®ãã©ãŒã ã¯ãDiagnosticDescriptorã«ãã£ãŠæäŸãããDiagnosticAnalyzer.SupportedDiagnosticsã 1 ã€ã ãã®ã¢ãã©ã€ã¶ãŒã®ãã¹ãã«ã®ã¿äœ¿çšã§ããŸãã -
{|ExpectedDiagnosticId:text|}: IdExpectedDiagnosticIdãå«ã蚺æãtextã«ã€ããŠå ±åãããããšã瀺ããŸãã
MakeConstUnitTest ã¯ã©ã¹ã®ãã³ãã¬ãŒã ãã¹ããæ¬¡ã®ãã¹ã ã¡ãœããã«çœ®ãæããŸãã
[TestMethod]
public async Task LocalIntCouldBeConstant_Diagnostic()
{
await VerifyCS.VerifyCodeFixAsync(@"
using System;
class Program
{
static void Main()
{
[|int i = 0;|]
Console.WriteLine(i);
}
}
", @"
using System;
class Program
{
static void Main()
{
const int i = 0;
Console.WriteLine(i);
}
}
");
}
ãã®ãã¹ããå®è¡ããŠãåæ Œããããšã確èªããŸãã Visual Studio ã§ãTest>> ãéžæããŠãã¹ã ãšã¯ã¹ãããŒã©ãŒãéããŸãã æ¬¡ã«ã[ ãã¹ãŠå®è¡] ãéžæããŸãã
æå¹ãªå®£èšã®ãã¹ããäœæãã
äžè¬çãªã«ãŒã«ãšããŠãã¢ãã©ã€ã¶ãŒã¯ã§ããã ãæ©ãçµäºããæå°éã®äœæ¥ãè¡ãå¿ èŠããããŸãã Visual Studio ã¯ããŠãŒã¶ãŒãã³ãŒããç·šéãããšãç»é²æžã¿ã®ã¢ãã©ã€ã¶ãŒãåŒã³åºããŸãã å¿çæ§ã¯éèŠãªèŠä»¶ã§ãã 蚺æãçºçãããã¹ãã§ã¯ãªãã³ãŒãã«ã¯ãããã€ãã®ãã¹ã ã±ãŒã¹ãååšããŸãã ã¢ãã©ã€ã¶ãŒã¯æ¢ã«ããã€ãã®ãã¹ããåŠçããŠããŸãã ãããã®ã±ãŒã¹ãè¡šãæ¬¡ã®ãã¹ã ã¡ãœããã远å ããŸãã
[TestMethod]
public async Task VariableIsAssigned_NoDiagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
class Program
{
static void Main()
{
int i = 0;
Console.WriteLine(i++);
}
}
");
}
[TestMethod]
public async Task VariableIsAlreadyConst_NoDiagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
class Program
{
static void Main()
{
const int i = 0;
Console.WriteLine(i);
}
}
");
}
[TestMethod]
public async Task NoInitializer_NoDiagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
class Program
{
static void Main()
{
int i;
i = 0;
Console.WriteLine(i);
}
}
");
}
ã¢ãã©ã€ã¶ãŒãæ¢ã«ãããã®æ¡ä»¶ãåŠçããŠããããããããã®ãã¹ãã¯æåããŸãã
- åæååŸã«å²ãåœãŠããã倿°ã¯ãããŒã¿ ãããŒåæã«ãã£ãŠæ€åºãããŸãã
- æ¢ã«
constãããŠãã宣èšã¯ãconstããŒã¯ãŒãã調ã¹ãŠé€å€ãããŸãã - åæååã®ãªã宣èšã¯ã宣èšå€ã®å²ãåœãŠãæ€åºããããŒã¿ ãããŒåæã«ãã£ãŠåŠçãããŸãã
次ã«ããŸã åŠçããŠããªãæ¡ä»¶ã®ãã¹ã ã¡ãœããã远å ããŸãã
åæååãã³ã³ãã€ã«æå®æ°ã«ã§ããªããããåæååã宿°ã§ã¯ãªã宣èš:
[TestMethod] public async Task InitializerIsNotConstant_NoDiagnostic() { await VerifyCS.VerifyAnalyzerAsync(@" using System; class Program { static void Main() { int i = DateTime.Now.DayOfYear; Console.WriteLine(i); } } "); }
C# ã§ã¯è€æ°ã®å®£èšã 1 ã€ã®ã¹ããŒãã¡ã³ããšããŠäœ¿çšã§ãããããããã«è€éã«ãªãå¯èœæ§ããããŸãã æ¬¡ã®ãã¹ã ã±ãŒã¹æåå宿°ã«ã€ããŠèããŠã¿ãŸãã
[TestMethod]
public async Task MultipleInitializers_NoDiagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
class Program
{
static void Main()
{
int i = 0, j = DateTime.Now.DayOfYear;
Console.WriteLine(i);
Console.WriteLine(j);
}
}
");
}
倿° i ã¯å®æ°ã«ã§ããŸããã倿° j ã§ããŸããã ãããã£ãŠããã®ã¹ããŒãã¡ã³ãã const 宣èšã«ããããšã¯ã§ããŸããã
ãã¹ããããäžåºŠå®è¡ãããšããããã®æåŸã® 2 ã€ã®ãã¹ã ã±ãŒã¹ã倱æããããšãããããŸãã
æ£ãã宣èšãç¡èŠããããã«ã¢ãã©ã€ã¶ãŒãæŽæ°ãã
ãããã®æ¡ä»¶ã«äžèŽããã³ãŒããé€å€ããã«ã¯ãã¢ãã©ã€ã¶ãŒã® AnalyzeNode ã¡ãœããã匷åããå¿
èŠããããŸãã ãããã®æ¡ä»¶ã¯ãã¹ãŠé¢é£ããŠãããããåæ§ã®å€æŽã«ãã£ãŠãããã®æ¡ä»¶ããã¹ãŠä¿®æ£ãããŸãã
AnalyzeNode ã«æ¬¡ã®å€æŽãå ããŸãã
- ã»ãã³ãã£ãã¯åæã§ã¯ã1 ã€ã®å€æ°å®£èšã調ã¹ãŸããã ãã®ã³ãŒãã¯ãåãã¹ããŒãã¡ã³ãã§å®£èšãããŠãããã¹ãŠã®å€æ°ã調ã¹ã
foreachã«ãŒãå ã«ããå¿ èŠããããŸãã - 宣èšãããå倿°ã«ã¯åæååãå¿ èŠã§ãã
- 宣èšãããå倿°ã®åæååã¯ãã³ã³ãã€ã«æå®æ°ã§ããå¿ èŠããããŸãã
AnalyzeNodeã¡ãœããã§ãå
ã®ã»ãã³ãã£ãã¯åæã眮ãæããŸãã
// Perform data flow analysis on the local declaration.
DataFlowAnalysis dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(localDeclaration);
// Retrieve the local symbol for each variable in the local declaration
// and ensure that it is not written outside of the data flow analysis region.
VariableDeclaratorSyntax variable = localDeclaration.Declaration.Variables.Single();
ISymbol variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
次ã®ã³ãŒã ã¹ããããã®ããã«ããŸãã
// Ensure that all variables in the local declaration have initializers that
// are assigned with constant values.
foreach (VariableDeclaratorSyntax variable in localDeclaration.Declaration.Variables)
{
EqualsValueClauseSyntax initializer = variable.Initializer;
if (initializer == null)
{
return;
}
Optional<object> constantValue = context.SemanticModel.GetConstantValue(initializer.Value, context.CancellationToken);
if (!constantValue.HasValue)
{
return;
}
}
// Perform data flow analysis on the local declaration.
DataFlowAnalysis dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(localDeclaration);
foreach (VariableDeclaratorSyntax variable in localDeclaration.Declaration.Variables)
{
// Retrieve the local symbol for each variable in the local declaration
// and ensure that it is not written outside of the data flow analysis region.
ISymbol variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
}
æåã® foreach ã«ãŒãã§ã¯ãæ§æåæã䜿çšããŠå倿°å®£èšã調ã¹ãŸãã æåã®ãã§ãã¯ã§ã¯ã倿°ã«åæååãããããšãä¿èšŒããŸãã 2 çªç®ã®ãã§ãã¯ã§ã¯ãåæååã宿°ã§ããããšãä¿èšŒãããŸãã 2 çªç®ã®ã«ãŒãã«ã¯ãå
ã®ã»ãã³ãã£ãã¯åæããããŸãã ã»ãã³ãã£ã㯠ãã§ãã¯ã¯ãããã©ãŒãã³ã¹ã«å€§ããªåœ±é¿ãäžãããããåå¥ã®ã«ãŒãå
ã«ãããŸãã ãã¹ããåå®è¡ãããã¹ãŠã®ãã¹ããæåããããšã確èªããŠãã ããã
æåŸã®ç 磚ã远å ãã
å®äºãŸã§ããå°ãã§ãã ã¢ãã©ã€ã¶ãŒãåŠçããæ¡ä»¶ã¯ä»ã«ãããã€ããããŸãã Visual Studio ã¯ããŠãŒã¶ãŒãã³ãŒããèšè¿°ããŠããéã«ã¢ãã©ã€ã¶ãŒãåŒã³åºããŸãã å€ãã®å Žåãã³ã³ãã€ã«ãããªãã³ãŒãã«å¯ŸããŠã¢ãã©ã€ã¶ãŒãåŒã³åºãããŸãã 蚺æã¢ãã©ã€ã¶ãŒã® AnalyzeNode ã¡ãœããã§ã¯ã宿°å€ã倿°åã«å€æã§ãããã©ããã確èªããŸããã ãããã£ãŠãçŸåšã®å®è£
ã§ã¯ã int i = "abc" ãªã©ã®æ£ãããªã宣èšãããŒã«ã«å®æ°ã«å€æãããŸãã ãã®å Žåã®ãã¹ã ã¡ãœããã远å ããŸãã
[TestMethod]
public async Task DeclarationIsInvalid_NoDiagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
class Program
{
static void Main()
{
int x = {|CS0029:""abc""|};
}
}
");
}
ãŸããåç
§åã¯æ£ããåŠçãããŸããã åç
§åã«äœ¿çšã§ãã宿°å€ã¯ãæååãªãã©ã«ãèš±å¯ãã null ã®å Žåãé€ããSystem.Stringã®ã¿ã§ãã ã€ãŸãã const string s = "abc" ã¯æå¹ã§ããã const object s = "abc" ã¯æå¹ã§ã¯ãããŸããã ãã®ã³ãŒã ã¹ããããã¯ããã®æ¡ä»¶ãæ€èšŒããŸãã
[TestMethod]
public async Task DeclarationIsNotString_NoDiagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
class Program
{
static void Main()
{
object s = ""abc"";
}
}
");
}
å®å šã«è¡ãã«ã¯ãå¥ã®ãã¹ãã远å ããŠãæååã®å®æ°å®£èšãäœæã§ããããšã確èªããå¿ èŠããããŸãã æ¬¡ã®ã¹ããããã§ã¯ã蚺æãçºçãããã³ãŒããšãä¿®æ£ããã°ã©ã ãé©çšãããåŸã®ã³ãŒãã®äž¡æ¹ãå®çŸ©ããŸãã
[TestMethod]
public async Task StringCouldBeConstant_Diagnostic()
{
await VerifyCS.VerifyCodeFixAsync(@"
using System;
class Program
{
static void Main()
{
[|string s = ""abc"";|]
}
}
", @"
using System;
class Program
{
static void Main()
{
const string s = ""abc"";
}
}
");
}
æåŸã«ã倿°ã var ããŒã¯ãŒãã§å®£èšãããŠããå Žåãã³ãŒãä¿®æ£ã«ãã£ãŠééã£ãåŠçãè¡ãããC# èšèªã§ãµããŒããããŠããªã const var 宣èšãçæãããŸãã ãã®ãã°ãä¿®æ£ããã«ã¯ã var ããŒã¯ãŒããæšè«ãããåã®ååã«çœ®ãæããå¿
èŠããããŸãã
[TestMethod]
public async Task VarIntDeclarationCouldBeConstant_Diagnostic()
{
await VerifyCS.VerifyCodeFixAsync(@"
using System;
class Program
{
static void Main()
{
[|var item = 4;|]
}
}
", @"
using System;
class Program
{
static void Main()
{
const int item = 4;
}
}
");
}
[TestMethod]
public async Task VarStringDeclarationCouldBeConstant_Diagnostic()
{
await VerifyCS.VerifyCodeFixAsync(@"
using System;
class Program
{
static void Main()
{
[|var item = ""abc"";|]
}
}
", @"
using System;
class Program
{
static void Main()
{
const string item = ""abc"";
}
}
");
}
幞ãã«ããäžèšã®ãã°ã¯ãã¹ãŠãåŠç¿ããã®ãšåãææ³ã䜿çšããŠå¯ŸåŠã§ããŸãã
æåã®ãã°ãä¿®æ£ããã«ã¯ã MakeConstAnalyzer.cs ãéããåããŒã«ã«å®£èšã®åæååããã§ãã¯ããã宿°å€ãå²ãåœãŠãããŠããããšã確èªãã foreach ã«ãŒããèŠã€ããŸãã æåã® ã«ãŒãã®foreachãcontext.SemanticModel.GetTypeInfo()ãåŒã³åºããŠãããŒã«ã«å®£èšã®å®£èšãããåã«é¢ãã詳现æ
å ±ãååŸããŸãã
TypeSyntax variableTypeName = localDeclaration.Declaration.Type;
ITypeSymbol variableType = context.SemanticModel.GetTypeInfo(variableTypeName, context.CancellationToken).ConvertedType;
次ã«ã foreach ã«ãŒãå
ã§ãååæååã倿°åã«å€æã§ããããšã確èªããŸãã åæååã宿°ã§ããããšã確èªããåŸã次ã®ãã§ãã¯ã远å ããŸãã
// Ensure that the initializer value can be converted to the type of the
// local declaration without a user-defined conversion.
Conversion conversion = context.SemanticModel.ClassifyConversion(initializer.Value, variableType);
if (!conversion.Exists || conversion.IsUserDefined)
{
return;
}
次ã®å€æŽã¯ãæåŸã®å€æŽã«åºã¥ããŠããŸãã æåã® foreach ã«ãŒãã®äžãã£ãã®åã«ã宿°ãæååãŸã㯠null ã®å Žåã«ããŒã«ã«å®£èšã®åãæ€æ»ããæ¬¡ã®ã³ãŒãã远å ããŸãã
// Special cases:
// * If the constant value is a string, the type of the local declaration
// must be System.String.
// * If the constant value is null, the type of the local declaration must
// be a reference type.
if (constantValue.Value is string)
{
if (variableType.SpecialType != SpecialType.System_String)
{
return;
}
}
else if (variableType.IsReferenceType && constantValue.Value != null)
{
return;
}
var ããŒã¯ãŒããæ£ããååã«çœ®ãæããã«ã¯ãã³ãŒãä¿®æ£ãããã€ããŒã«ããå°ãã³ãŒããèšè¿°ããå¿
èŠããããŸãã
MakeConstCodeFixProvider.csã«æ»ããŸãã 远å ããã³ãŒãã§ã¯ãæ¬¡ã®æé ãå®è¡ããŸãã
- 宣èšã
var宣èšã§ãããã©ããã確èªããããã§ããã°ä»¥äžã®æé ãå®è¡ããŠãã ããã - æšè«ãããåã®æ°ããåãäœæããŸãã
- å宣èšããšã€ãªã¢ã¹ã§ã¯ãªãããšã確èªããŸãã ãã®å Žåã¯ã
const varã宣èšããããšã¯æå¹ã§ãã -
varããã®ããã°ã©ã ã®ååã§ã¯ãªãããšã確èªããŸãã (ãã®å Žåãconst varã¯æå¹ã§ã)ã - å®å šãªååãç°¡ç¥åãã
ããã¯å€ãã®ã³ãŒãã®ããã«èãããŸãã ãããããããŸããã
newLocalã宣èšããŠåæåããè¡ã次ã®ã³ãŒãã«çœ®ãæããŸãã ããã¯ã newModifiersã®åæåçŽåŸã«è¡ãããŸãã
// If the type of the declaration is 'var', create a new type name
// for the inferred type.
VariableDeclarationSyntax variableDeclaration = localDeclaration.Declaration;
TypeSyntax variableTypeName = variableDeclaration.Type;
if (variableTypeName.IsVar)
{
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
// Special case: Ensure that 'var' isn't actually an alias to another type
// (e.g. using var = System.String).
IAliasSymbol aliasInfo = semanticModel.GetAliasInfo(variableTypeName, cancellationToken);
if (aliasInfo == null)
{
// Retrieve the type inferred for var.
ITypeSymbol type = semanticModel.GetTypeInfo(variableTypeName, cancellationToken).ConvertedType;
// Special case: Ensure that 'var' isn't actually a type named 'var'.
if (type.Name != "var")
{
// Create a new TypeSyntax for the inferred type. Be careful
// to keep any leading and trailing trivia from the var keyword.
TypeSyntax typeName = SyntaxFactory.ParseTypeName(type.ToDisplayString())
.WithLeadingTrivia(variableTypeName.GetLeadingTrivia())
.WithTrailingTrivia(variableTypeName.GetTrailingTrivia());
// Add an annotation to simplify the type name.
TypeSyntax simplifiedTypeName = typeName.WithAdditionalAnnotations(Simplifier.Annotation);
// Replace the type in the variable declaration.
variableDeclaration = variableDeclaration.WithType(simplifiedTypeName);
}
}
}
// Produce the new local declaration.
LocalDeclarationStatementSyntax newLocal = trimmedLocal.WithModifiers(newModifiers)
.WithDeclaration(variableDeclaration);
usingåã䜿çšããã«ã¯ã1 ã€ã®Simplifier ãã£ã¬ã¯ãã£ãã远å ããå¿
èŠããããŸãã
using Microsoft.CodeAnalysis.Simplification;
ãã¹ããå®è¡ãããšããã¹ãŠãæåããã¯ãã§ãã 宿ããã¢ãã©ã€ã¶ãŒãå®è¡ããŠãèªåãè€ããŸãããã Ctrl+ããŒãæŒããŠãRoslyn Preview æ¡åŒµæ©èœãèªã¿èŸŒãŸãã Visual Studio ã® 2 çªç®ã®ã€ã³ã¹ã¿ã³ã¹ã§ã¢ãã©ã€ã¶ãŒ ãããžã§ã¯ããå®è¡ããŸãã
- 2 çªç®ã® Visual Studio ã€ã³ã¹ã¿ã³ã¹ã§ãæ°ãã C# ã³ã³ãœãŒã« ã¢ããªã±ãŒã·ã§ã³ ãããžã§ã¯ããäœæããmain ã¡ãœããã«
int x = "abc";ã远å ããŸãã æåã®ãã°ä¿®æ£ã«ããããã®ããŒã«ã«å€æ°å®£èšã«å¯ŸããèŠåã¯å ±åãããŸãã (ãã ããã³ã³ãã€ã© ãšã©ãŒã¯æ³å®ã©ããã«çºçããŸã)ã - 次ã«ãMain ã¡ãœããã«
object s = "abc";ã远å ããŸãã 2 ã€ç®ã®ãã°ä¿®æ£ã«ãããèŠåã¯å ±åãããŸããã - æåŸã«ã
varããŒã¯ãŒãã䜿çšããå¥ã®ããŒã«ã«å€æ°ã远å ããŸãã èŠåãå ±åãããå·Šäžã«ææ¡ã衚瀺ãããŸãã - æ³¢ç·ã«ãšãã£ã¿ãŒã®ã«ã¬ãããç§»åããCtrl+. ããŒãæŒããŸãã æšå¥šãããã³ãŒãä¿®æ£ã衚瀺ããŸãã ã³ãŒãä¿®æ£ããã°ã©ã ãéžæãããšã
varããŒã¯ãŒããæ£ããåŠçãããããšã«æ³šæããŠãã ããã
æåŸã«ã次ã®ã³ãŒãã远å ããŸãã
int i = 2;
int j = 32;
int k = i + j;
ãããã®å€æŽã®åŸã¯ãæåã® 2 ã€ã®å€æ°ã«ã®ã¿èµ€ãæ³¢ç·ã衚瀺ãããŸãã
constãšiã®äž¡æ¹ã«jã远å ãããšãkãconstã§ããããã«ãªã£ããããæ°ããèŠåã衚瀺ãããŸãã
ããã§ãšãããããŸã! æåã® .NET ã³ã³ãã€ã© ãã©ãããã©ãŒã æ¡åŒµæ©èœãäœæããŸããããã®æ¡åŒµæ©èœã¯ãåé¡ãæ€åºããããã®ãªã³ã¶ãã©ã€ ã³ãŒãåæãå®è¡ããä¿®æ£ããããã®ç°¡åãªä¿®æ£ããã°ã©ã ãæäŸããŸãã ãã®éçšã§ã.NET Compiler Platform SDK (Roslyn API) ã®äžéšã§ããã³ãŒã API ã®å€ããåŠç¿ããŸããã ãµã³ãã« GitHub ãªããžããªã® 宿ãããµã³ãã« ã«å¯ŸããŠäœæ¥ã確èªã§ããŸãã